I'm using the Android CardsLib to generate a list of cards in my fragment. I've the list properly done, no problem here.
Now I'm following the tutorial (link to the tutorial) to add MultiChoiceMode to my list, this is selecting multiple cards using the long tap/click to select. But I'm getting a NullPointerException
.
Here's my stacktrace:
FATAL EXCEPTION: main
Process: com.mypackage.android.design.appdesgin, PID: 18937
java.lang.NullPointerException
at it.gmariotti.cardslib.library.internal.multichoice.MultiChoiceAdapterHelperBase.onItemSelectedStateChanged(MultiChoiceAdapterHelperBase.java:293)
at it.gmariotti.cardslib.library.internal.multichoice.MultiChoiceAdapterHelperBase.onCreateActionMode(MultiChoiceAdapterHelperBase.java:255)
at it.gmariotti.cardslib.library.internal.CardArrayMultiChoiceAdapter.onCreateActionMode(CardArrayMultiChoiceAdapter.java:131)
at com.mypackage.android.design.appdesgin.cards.MyCardArrayMultiChoiceAdapter.onCreateActionMode(MyCardArrayMultiChoiceAdapter.java:31)
at com.android.internal.policy.impl.PhoneWindow$DecorView$ActionModeCallbackWrapper.onCreateActionMode(PhoneWindow.java:3011)
at com.android.internal.app.ActionBarImpl$ActionModeImpl.dispatchOnCreate(ActionBarImpl.java:909)
at com.android.internal.app.ActionBarImpl.startActionMode(ActionBarImpl.java:453)
at android.app.Activity.onWindowStartingActionMode(Activity.java:5005)
at com.android.internal.policy.impl.PhoneWindow$DecorView.startActionMode(PhoneWindow.java:2636)
at android.app.Activity.startActionMode(Activity.java:4987)
at it.gmariotti.cardslib.library.internal.multichoice.MultiChoiceAdapterHelperBase.startActionMode(MultiChoiceAdapterHelperBase.java:239)
at it.gmariotti.cardslib.library.internal.CardArrayMultiChoiceAdapter.startActionMode(CardArrayMultiChoiceAdapter.java:117)
at com.mypackage.android.design.appdesgin.fragments.CardLocalBackupsFragment$1.onLongClick(CardLocalBackupsFragment.java:152)
at it.gmariotti.cardslib.library.view.CardView$5.onLongClick(CardView.java:533)
at android.view.View.performLongClick(View.java:4481)
at android.view.View$CheckForLongPress.run(View.java:18425)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5081)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
at dalvik.system.NativeStart.main(Native Method)
The null pointer is here:
protected void onItemSelectedStateChanged(ActionMode mode) {
int count = mAdapterView.getCheckedItemCount(); // mAdapterView is NULL
if (count > 0) {
Resources res = mAdapterView.getResources();
String mTitleSelected = res.getQuantityString(R.plurals.card_selected_items, count, count);
mode.setTitle(mTitleSelected);
}
}
but this code belongs to MultiChoiceAdapterHelperBase
which is part of cardlib's code.
Following the stacktrace it leads to this class (which I copied from the tutorial), MyCardArrayMultiChoiceAdapter
which has this code (NPE is on the call to super on onCreateActionMode
)
public class MyCardArrayMultiChoiceAdapter extends CardArrayMultiChoiceAdapter {
private ActionMode mActionMode;
public MyCardArrayMultiChoiceAdapter(Context context, List<Card> cards) {
super(context, cards);
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
//It is very important to call the super method
super.onCreateActionMode(mode, menu); // This is line 31 where it says in my stacktrace
mActionMode = mode; // to manage mode in your Fragment/Activity
//If you would like to inflate your menu
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.carddemo_multichoice, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// if (item.getItemId() == R.id.menu_share) {
// Toast.makeText(getContext(), "Share;" + formatCheckedCard(), Toast.LENGTH_SHORT).show();
// return true;
// }
if (item.getItemId() == R.id.menu_discard) {
discardSelectedItems(mode);
return true;
}
return false;
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked, CardView cardView, Card card) {
Toast.makeText(getContext(), "Click;" + position + " - " + checked, Toast.LENGTH_SHORT).show();
}
private void discardSelectedItems(ActionMode mode) {
ArrayList<Card> items = getSelectedCards();
for (Card item : items) {
remove(item);
}
mode.finish();
}
private String formatCheckedCard() {
SparseBooleanArray checked = mCardListView.getCheckedItemPositions();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < checked.size(); i++) {
if (checked.valueAt(i) == true) {
sb.append("\nPosition=" + checked.keyAt(i));
}
}
return sb.toString();
}
}
Can anyone figure out why this null point exception? Or what am I doing wrong to implement multichoice mode in my cardslist?
If there's the need to put more code here let me know and I'll edit this question.
Found the problem.
I was still using CardArrayAdapter
on my fragment that has the list. I moved from CardArrayAdapter
to CardArrayMultiChoiceAdapter
and it is working flawlessly :)
So I had something like (on my fragment):
private CardArrayAdapter cardArrayAdapter; // comment this one
private MyCardArrayMultiChoiceAdapter cardArrayAdapter; // use this one!
has in the tutorial:
If you would like to have a CardList with a MultiChoiceMode built-in feature you can use a CardArrayMultiChoiceAdapter.
This class extends CardArrayAdapter and preserves all its features.