Reputation: 633
I have a RecyclerView
in my MainActivity.java
. In each RecyclerView row, I have a button, and when it's pressed, it supposed to open a customized fragment dialog with RecyclerView list in it (it's a multi-choice dialog).
In my SecondActivity.java
, which is my other activity, I also have the same button which is supposed to do the same thing (this is why I need the modal to be the fragment dialog). In my SecondActivity.java
, there is no RecyclerView, it's just a single post (detail page).
My problem:
When I click on the button for the popup on SecondActivity.java
, it opens the dialog fragment popup normally. When I do the same for any individual row in my RecyclerView (which is in MainActivity.java
), I get a ClassCastException
error:
java.lang.ClassCastException: com.example.appname.MainActivity cannot be cast to interfaces.DialogCommunicator$Communicator
My code:
SecondActivity.java
//*****************//
// THIS CODE WORKS //
//*****************//
// This code will run when the button is clicked.
// postOptions is a string array of menu items.
Bundle args = new Bundle();
args.putStringArray("displaymenu", postOptions);
mDialogFragment = new CustomDialogFragment();
mDialogFragment.setArguments(args);
mDialogFragment.show(getSupportFragmentManager(), "title");
PostsListAdapter.java
//***************************//
// THIS CODE CRASHES THE APP //
//***************************//
// This code is planted in onClick method listener in onBindViewHolder
// for the button that's supposed to open the fragment dialog.
FragmentManager fm = ((MainActivity) mContext).getSupportFragmentManager();
String[] items = mContext.getResources().getStringArray(R.array.post_options);
CustomDialogFragment customDialogFragment = CustomDialogFragment.newInstance(items);
customDialogFragment.show(fm, "title");
CustomDialogFragment.java
public class CustomDialogFragment extends DialogFragment {
private RecyclerView mRecyclerView;
public CustomDialogFragment() {
// Empty constructor is required for DialogFragment
// Make sure not to add arguments to the constructor
// Use `newInstance` instead as shown below
}
public static CustomDialogFragment newInstance(String[] items) {
CustomDialogFragment customDialogFragment = new CustomDialogFragment();
Bundle args = new Bundle();
args.putStringArray("displaymenu", items);
customDialogFragment.setArguments(args);
return customDialogFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.layout_multiselect_dialog, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle args = getArguments();
String[] items = args.getStringArray("displaymenu");
List<String> itemsList = Arrays.asList(items);
// THIS LINE CRASHES ON POSTSLISTADAPTER!!!
MultiDialogAdapter adapter = new MultiDialogAdapter(getActivity(), itemsList);
mRecyclerView = (RecyclerView) view.findViewById(R.id.items_recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setAdapter(adapter);
getDialog().setTitle(null);
}
}
MultiDialogAdapter.java
public class MultiDialogAdapter extends RecyclerView.Adapter<MultiDialogViewHolder> {
private List<String> mItems;
private LayoutInflater mInflater;
private CustomFonts mCustomFont;
private DialogCommunicator.Communicator mCommunicator;
public MultiDialogAdapter(Context context, List<String> items) {
this.mInflater = LayoutInflater.from(context);
this.mItems = items;
this.mCustomFont = new CustomFonts(context);
try {
mCommunicator = (DialogCommunicator.Communicator) context;
} catch (ClassCastException e) {
// THIS IS WHERE THE CLASSCASTEXCEPTION HAPPENS!
throw new ClassCastException(context.toString());
}
}
@Override
public MultiDialogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.layout_multiselect_dialog_row, parent, false);
return new MultiDialogViewHolder(view);
}
@Override
public void onBindViewHolder(MultiDialogViewHolder holder, int position) {
final String item = mItems.get(position);
holder.getItemTextView().setText(item);
holder.getItemTextView().setTypeface(mCustomFont.getPrimaryFontMedium());
holder.getItemTextView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCommunicator.onDialogButtonResponse(item);
}
});
}
@Override
public int getItemCount() {
return mItems.size();
}
}
class MultiDialogViewHolder extends RecyclerView.ViewHolder {
private TextView mItemTextView;
public MultiDialogViewHolder(View rootView) {
super(rootView);
mItemTextView = (TextView) rootView.findViewById(R.id.item_text_view);
}
public TextView getItemTextView() {
return mItemTextView;
}
}
DialogCommunicator.java
public class DialogCommunicator {
public interface Communicator {
public void onDialogButtonResponse(String responseMessage);
}
}
Crash log:
10-06 14:35:12.353 21683-21683/com.example.appname E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.appname, PID: 21683
java.lang.ClassCastException: com.example.appname.MainActivity@e06db1e
at adapters.MultiDialogAdapter.<init>(MultiDialogAdapter.java:40)
at fragments.CustomDialogFragment.onViewCreated(CustomDialogFragment.java:60)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1430)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
I have that interface which is implemented in PostsListAdapter.java
and SecondActivity.java
. This is a callback method so I can respond to each individual action and know what item is clicked inside the fragment dialog popup.
So, I have built the dialog fragment correctly because it works in a normal activity outside of a list, but for each row in a RecyclerView list, that dialog fragment crashes the app because of the ClassCastException
. Why?
Upvotes: 0
Views: 779
Reputation: 4132
Instead of passing context as a object you can get the construtor in the onCreateViewHolder using parent.getContext().
Also in the onBindViewholder you forgot to typecast viewholder.Add
MultiDialogViewHolder viewholder=(MultiDialogViewHolder)holder;
Then access viewholder.getItemTextView().setText(item);
Also before typcasting the context in adapter your dialog fragment should implement DialogCommunicator
.Add implementaion of DialogCommunicator
in the dialog fragment
public class CustomDialogFragment extends DialogFragment implements DialogCommunicator {
//override the method
}
EDIT:
Also main problem the error occuring is because of the context.
Here pass MultiDialogAdapter adapter=new MultiDialogAdapter(getContext(), itemsList)
.
If your are passing getActivity() to the adapter then your corresponding activity has to implement the interface DialogCommunicator
and the callback comes to activity instead of CustomDialogFragment
.
So pass getContext()
instead of getActivity()
because CustomDialogFragment is implementing the interface and not the activity.
Upvotes: 3
Reputation: 54194
Your crash is very explicit:
MainActivity
cannot be cast toDialogCommunicator$Communicator
According to what you've posted, you have not implemented this interface in MainActivity
. You said:
I have that interface which is implemented in
PostsListAdapter.java
andSecondActivity.java
.
Chances are extremely good that you should remove the implements DialogCommunicator.Communicator
line from PostsListAdapter
and add it to MainActivity
instead (and move the actual implementation as well, of course).
The nitty-gritty cause is this line:
MultiDialogAdapter adapter = new MultiDialogAdapter(getActivity(), itemsList);
You're passing getActivity()
as the Context
argument to your adapter's constructor. This would be fine, except that your dialog's constructor then casts this Context
instance to your interface. So every Activity
that this dialog could be shown in must implement your interface.
Upvotes: 2