I'm trying to convert Activity to Fragment and I'm sruggling to understand how to do it properly with this one.
Basically, I'm trying to adapt this MainActivity so as it fits a bottom navigation bar and besides getting lost in contexts, I'm dealing with this specific issue:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.com, PID: 5213 java.lang.ClassCastException: com.example.com.MainActivity cannot be cast to com.example.com.adapter.NotesAdapter$OnNoteItemClick at com.example.com.adapter.NotesAdapter.(NotesAdapter.java:27) at com.example.com.RoomMarkdownActivity.onCreateView(RoomMarkdownActivity.java:54) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:733) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 5213 SIG: 9 Application terminated.
Here is a copy of the piece of code I'm working on:
public class RoomMarkdownActivity extends Fragment implements NotesAdapter.OnNoteItemClick {
public static RoomMarkdownActivity newInstance() { return new RoomMarkdownActivity(); }
public RecyclerView recyclerView;
public TextView textViewMsg;
public NoteDatabase noteDatabase;
public List<Note> notes;
public NotesAdapter notesAdapter;
public int pos;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.room_markdown_activity, container, false);
textViewMsg = view.findViewById(R.id.textview_empty);
FloatingActionButton fab = view.findViewById(R.id.fab);
fab.setOnClickListener(listener);
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
notes = new ArrayList<>();
notesAdapter = new NotesAdapter(notes, getActivity());
recyclerView.setAdapter(notesAdapter);
noteDatabase = NoteDatabase.getInstance(getActivity());
new RetrieveTask(this).execute();
return view;
}
private static class RetrieveTask extends AsyncTask<Void, Void, List<Note>> {
private WeakReference<RoomMarkdownActivity> activityReference;
RetrieveTask(RoomMarkdownActivity context) {
activityReference = new WeakReference<>(context);
}
@Override
protected List<Note> doInBackground(Void... voids) {
if (activityReference.get() != null)
return activityReference.get().noteDatabase.getNoteDao().getNotes();
else
return null;
}
@Override
protected void onPostExecute(List<Note> notes) {
if (notes != null && notes.size() > 0) {
activityReference.get().notes.clear();
activityReference.get().notes.addAll(notes);
activityReference.get().textViewMsg.setVisibility(View.GONE);
activityReference.get().notesAdapter.notifyDataSetChanged();
}
}
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivityForResult(new Intent(getActivity(), RoomMarkdownAddNoteActivity.class), 100);
}
};
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100 && resultCode > 0) {
if (resultCode == 1) {
notes.add((Note) data.getSerializableExtra("note"));
} else if (resultCode == 2) {
notes.set(pos, (Note) data.getSerializableExtra("note"));
}
listVisibility();
}
}
@Override
public void onNoteClick(final int pos) {
new AlertDialog.Builder(recyclerView.getContext())
.setTitle("Select:")
.setItems(new String[]{"Read", "Update", "Delete"}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0:
RoomMarkdownActivity.this.pos = pos;
startActivityForResult(
new Intent(getActivity(),
RoomMarkdownViewNoteActivity.class).putExtra(
"note", notes.get(pos)), 100);
break;
case 1:
RoomMarkdownActivity.this.pos = pos;
startActivityForResult(
new Intent(getActivity(),
RoomMarkdownAddNoteActivity.class).putExtra(
"note", notes.get(pos)), 100);
break;
case 2:
noteDatabase.getNoteDao().deleteNote(notes.get(pos));
notes.remove(pos);
listVisibility();
break;
}
}
}).show();
}
private void listVisibility() {
int emptyMsgVisibility = View.GONE;
if (notes.size() == 0) {
if (textViewMsg.getVisibility() == View.GONE)
emptyMsgVisibility = View.VISIBLE;
}
textViewMsg.setVisibility(emptyMsgVisibility);
notesAdapter.notifyDataSetChanged();
}
@Override
public void onDestroy() {
noteDatabase.cleanUp();
super.onDestroy();
}
}
And here is the adapter:
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.BeanHolder> {
private List<Note> list;
public Context context;
private LayoutInflater layoutInflater;
private OnNoteItemClick onNoteItemClick;
public NotesAdapter(List<Note> list, Context context) {
layoutInflater = LayoutInflater.from(context);
this.list = list;
this.context = context;
this.onNoteItemClick = (OnNoteItemClick) context;
}
@Override
public BeanHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.room_markdown_note_list_item, parent, false);
return new BeanHolder(view);
}
@Override
public void onBindViewHolder(BeanHolder holder, int position) {
Log.e("bind", "onBindViewHolder: " + list.get(position));
holder.textViewTitle.setText(list.get(position).getTitle());
}
@Override
public int getItemCount() {
return list.size();
}
public class BeanHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textViewTitle;
private BeanHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textViewTitle = itemView.findViewById(R.id.textview_title);
}
@Override
public void onClick(View view) {
onNoteItemClick.onNoteClick(getAdapterPosition());
}
}
public interface OnNoteItemClick {
void onNoteClick(int pos);
}
}
It seems there's something broken between notesAdapter = new NotesAdapter(notes, getActivity()); and this.onNoteItemClick = (OnNoteItemClick) context;, but I couldn't find a good alternative to getActivity() and I guess I solved this one earlier in another approach, however, it was still throwing another similar error if I recall correctly (this file is full of this and I don't doubt some getActivity() are misplaced).
The code as is compiles, but, as soon as the button that'd call the specific Fragment to the screen is clicked, the error is thrown and the app stops running immediately.
I thank you in advance for the attention and help and, please, let me know if you need to know more about this issue so as I'm able to bring more information here.
getActivity()for theContextparameter in yourNotesAdapterconstructor call. That's theActivityhosting theFragment, not theFragmentitself. YourActivityapparently does not implement theOnNoteItemClickinterface, which is why you get thatException. You want to pass theFragment– i.e.,this– as theOnNoteItemClickimplementer. You could change theContextparameter toFragment, cast that as your interface, and do thegetActivity()call in the constructor to get yourContext.