I am trying to implement swipe to delete in RecyclerView. Everything seems to be working fine except drawing a delete icon below the item that's being swiped.
This is how I am doing it:
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
// Do my stuff
// }
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
Bitmap icon;
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
View itemView = viewHolder.itemView;
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
if(dX > 0){
p.setColor(Color.parseColor("#388E3C"));
RectF background = new RectF((float) itemView.getLeft(), (float) itemView.getTop(), dX,(float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_delete);
RectF icon_dest = new RectF((float) itemView.getLeft() + width ,(float) itemView.getTop() + width,(float) itemView.getLeft()+ 2*width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,p);
} else {
p.setColor(Color.parseColor("#D32F2F"));
RectF background = new RectF((float) itemView.getRight() + dX, (float) itemView.getTop(),(float) itemView.getRight(), (float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_delete);
RectF icon_dest = new RectF((float) itemView.getRight() - 2*width ,(float) itemView.getTop() + width,(float) itemView.getRight() - width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,p);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
It is throwing
java.lang.NullPointerException: Attempt to invoke virtual method
'boolean android.graphics.Bitmap.isRecycled()' on a null object
reference
Full StackTrace
09-12 01:28:58.386 26575-26575/com.ozuf.booker E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ozuf.booker, PID: 26575
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.isRecycled()' on a null object reference
at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1281)
at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:620)
at com.ozuf.booker.fragments.BookFragment$1.onChildDraw(BookFragment.java:149)
at android.support.v7.widget.helper.ItemTouchHelper$Callback.onDraw(ItemTouchHelper.java:1956)
at android.support.v7.widget.helper.ItemTouchHelper$Callback.access$1400(ItemTouchHelper.java:1356)
at android.support.v7.widget.helper.ItemTouchHelper.onDraw(ItemTouchHelper.java:542)
at android.support.v7.widget.RecyclerView.onDraw(RecyclerView.java:3373)
at android.view.View.draw(View.java:15635)
at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3308)
at android.view.View.updateDisplayListIfDirty(View.java:14568)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3588)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3567)
at android.view.View.updateDisplayListIfDirty(View.java:14528)
at android.view.View.getDisplayList(View.java:14590)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2575)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2385)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2012)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1073)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5988)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Chor
Line 149 is c.drawBitmap(icon,null,icon_dest,p);
I have debugged and I saw that icon
is null but I don't understand why it;s null since I've already assigned it a value.
Best Answer
Yes. You did =>
null
. The problem is elsewhere. See docs for decodeResource():so you need to a) always check for that condition, b) check why exactly it happens with the data you try to decode.