I have a RecyclerView
inside a AppCompatActivity
. Item insertions and changes are shown and animated correctly after rotating the device.
The problem happens when you:
- Tap on an item in the
RecyclerView
. - A
DialogFragment
opens prompting if you want to the delete the item. - Rotate the device.
- Confirm the deletion in the dialog.
- Check the array list. The item has been deleted.
- The
RecyclerView
still shows the item.
Tried using notifyDataSetChanged
instead of notifyItemRemoved
but didn't work either because the item is still being shown in the RecyclerView
.
This is happening with any version of Android.
Simplified code of how the process is being handled:
public class MyAppCompatActivity extends AppCompatActivity {
int positionOfDeletedItem;
MyObjectRecyclerViewAdapter adapter;
ArrayList<MyObject> someTestData;
MyItemDeletionHandler deletionHandlerRemover;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity_layout);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
positionOfDeletedItem = 1;
deletionHandlerRemover = new MyItemDeletionHandler(this);
someTestData = new ArrayList<MyObject>(3);
someTestData.add(new MyObject("A"));
someTestData.add(new MyObject("B"));
someTestData.add(new MyObject("C"));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyObjectRecyclerViewAdapter(new MyAdapterOnClickEvent.OnItemClick() {
@Override
public void onClick(int posicion, int idViaje, View view) {
String tag = "Some tag value";
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag(tag);
if(prev != null)
ft.remove(prev);
ft.addToBackStack(null);
DialogFragment newFragment = MyDeletionConfirmationDialog.newInstance(deletionHandlerRemover);
newFragment.show(ft, tag);
}
}, someTestData);
recyclerView.setAdapter(adapter);
}
private final static class MyItemDeletionHandler extends Handler {
private final WeakReference<MyAppCompatActivity> theActivity;
private MyItemDeletionHandler(MyAppCompatActivity act) {
theActivity = new WeakReference<MyAppCompatActivity>(act);
}
@Override
public void handleMessage(Message msg) {
MyAppCompatActivity activity = theActivity.get();
if(activity != null) {
if(msg.what == 1) {
activity.deleteTheItem();
}
}
}
}
public void deleteTheItem() {
someTestData.remove(positionOfDeletedItem);
adapter.notifyItemRemoved(positionOfDeletedItem);
}
}
public class MyDeletionConfirmationDialog extends DialogFragment {
private Message handlerMessage;
public static MyDeletionConfirmationDialog newInstance(Handler callbackHandler) {
MyDeletionConfirmationDialog myDialog = new MyDeletionConfirmationDialog();
Bundle args = new Bundle();
args.putParcelable("handlerMessage", callbackHandler.obtainMessage(1, true));
myDialog.setArguments(args);
return myDialog;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handlerMessage = getArguments().getParcelable("handlerMessage");
}
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setMessage("Some message");
alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
final Message toSend = Message.obtain(handlerMessage);
toSend.sendToTarget();
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
Dialog dialog = alertDialogBuilder.create();
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
}
How can I get the RecyclerView
to work correctly?
Edit 1:
I have other RecyclerView
s in which this works correctly. The only difference is those are inside Fragment
s instead of AppCompatActivity
. I am suspecting that this has something to do with the events onDetachedFromWindow
and onAttachedToWindow
of the RecyclerView
.
Edit 2:
If the dialog is closed (step 4) and opened again it works as expected.
Edit 3:
If the RecyclerView
is extracted as a Fragment
the problem disappears and works as intended. It is impossible to have the use case described above working correctly in conjunction with AppCompatActivity
instead of a Fragment
.
RecyclerView
isn't updated accordingly, it still shows the deleted item. – BickonConfigurationChange
and can dismiss the dialogue which is showing in the screen. The dialogue showing in the screen is not related to the activity/fragment lifecycle and that's why it remains on the screen. – McnewRecyclerViews
that follow the same use case and are working correctly. This one just baffled me. I'll update my question with some assumption I think might be causing the problem. – BickMyItemDeletionHandler
should not compile as written. It's a static inner class, so it should not have access to instance members ofMyAppCompatActivity
. – FimbriateMyDeletionConfirmationDialog
? – FimbriateDialogFragment
that in the methodonCreateDialog
usesAlertDialog.Builder
to create a dialog, and assigns in thesetPositiveButton
a listener that executesfinal Message toSend = Message.obtain(callbackHandler.obtainMessage(1, true)); toSend.sendToTarget();
. Is that enough or need full code? In Summary is a simple confirmation dialog. – BickNullPointerException
when you callsendToTarget()
on that Message object. – FimbriateLoaderManager
. But I reposted the code with a simplified version without database access that still shows the problem. I'll update the description. – Bick