Ho un RecyclerView
all'interno di un AppCompatActivity
. Gli inserimenti e le modifiche degli elementi vengono mostrati e animati correttamente dopo aver ruotato il dispositivo.RecyclerView non si aggiorna dopo aver ruotato il dispositivo con un DialogFragment aperto
Il problema si verifica quando si:
- Toccare un elemento nella
RecyclerView
. - A
DialogFragment
apre il prompt se si desidera eliminare l'elemento. - Ruota il dispositivo.
- Confermare la cancellazione nella finestra di dialogo.
- Controllare l'elenco di array. L'oggetto è stato cancellato.
- Il
RecyclerView
mostra ancora l'elemento.
provato ad utilizzare notifyDataSetChanged
invece di notifyItemRemoved
, ma non ha funzionato o perché la voce è ancora mostrato nel RecyclerView
.
Questo sta accadendo con qualsiasi versione di Android.
semplificato il codice di come il processo viene gestita:
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;
}
}
Come posso ottenere il RecyclerView
per funzionare correttamente?
Edit 1:
ho altri RecyclerView
s in cui questo funziona correttamente. L'unica differenza è che sono all'interno di Fragment
s anziché AppCompatActivity
. Sospetto che questo abbia qualcosa a che fare con gli eventi onDetachedFromWindow
e onAttachedToWindow
dello RecyclerView
.
Edit 2:
Se la finestra è chiusa (fase 4) e riaperto funziona come previsto.
Edit 3:
Se il RecyclerView
viene estratto come un Fragment
il problema scompare e funziona come previsto. È impossibile che il caso d'uso descritto sopra funzioni correttamente insieme a AppCompatActivity
anziché a Fragment
.
Quando si fa clic sulla finestra di dialogo, questo dovrebbe scomparire e cancellare l'elemento nell'elenco. Quindi, come mai il dialogo rimane quando cambi l'orientamento e cancella i dati? –
@ReazMurshed Il caso d'uso è il seguente: Fai clic su un elemento per eliminarlo. Mostra una finestra di conferma con le opzioni ('Annulla' e 'Elimina'). Non fai clic su nessuna delle opzioni. Ruota il dispositivo. La finestra di dialogo è ancora aperta. Quindi scegli l'opzione 'Elimina' per eliminare l'elemento. La finestra di dialogo si chiude. L'oggetto è stato cancellato dal database. Il 'RecyclerView' non viene aggiornato di conseguenza, mostra ancora l'elemento eliminato. – OneEyeQuestion
Questa non è una soluzione adeguata, ma in ogni caso, questo hack può fare il trucco che vuoi. È possibile rilevare facilmente la modifica dell'orientamento in 'onConfigurationChange' e può chiudere il dialogo visualizzato sullo schermo. Il dialogo visualizzato sullo schermo non è correlato al ciclo di vita di attività/frammento ed è per questo che rimane sullo schermo. –