TL; DR Concludi le tue navigate
chiamate con try-catch
(modo semplice), o assicurati che ci sarà solo una chiamata di navigate
in un breve periodo di tempo. Questo problema probabilmente non scomparirà. Copia uno snippet di codice più grande nella tua app e provalo.
Ciao. Sulla base di un paio di risposte utili sopra, vorrei condividere la mia soluzione che può essere estesa.
Ecco il codice che ha causato questo arresto anomalo nella mia applicazione:
@Override
public void onListItemClicked(ListItem item) {
Bundle bundle = new Bundle();
bundle.putParcelable(SomeFragment.LIST_KEY, item);
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
}
Un modo per riprodurre facilmente il bug è toccare con più dita l'elenco di elementi in cui il clic su ciascun elemento si risolve nella navigazione verso la nuova schermata (fondamentalmente lo stesso come notato dalle persone: due o più clic in un periodo di tempo molto breve ). Ho notato che:
- Primo
navigate
chiamata funziona sempre bene;
- La seconda e tutte le altre invocazioni del
navigate
metodo si risolvono in IllegalArgumentException
.
Dal mio punto di vista, questa situazione può apparire molto spesso. Poiché la ripetizione del codice è una cattiva pratica ed è sempre bene avere un punto di influenza, ho pensato alla soluzione successiva:
public class NavigationHandler {
public static void navigate(View view, @IdRes int destination) {
navigate(view, destination, /* args */null);
}
/**
* Performs a navigation to given destination using {@link androidx.navigation.NavController}
* found via {@param view}. Catches {@link IllegalArgumentException} that may occur due to
* multiple invocations of {@link androidx.navigation.NavController#navigate} in short period of time.
* The navigation must work as intended.
*
* @param view the view to search from
* @param destination destination id
* @param args arguments to pass to the destination
*/
public static void navigate(View view, @IdRes int destination, @Nullable Bundle args) {
try {
Navigation.findNavController(view).navigate(destination, args);
} catch (IllegalArgumentException e) {
Log.e(NavigationHandler.class.getSimpleName(), "Multiple navigation attempts handled.");
}
}
}
E quindi il codice sopra cambia solo in una riga da questo:
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
a questa:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
È persino diventato un po 'più corto. Il codice è stato testato nel punto esatto in cui si è verificato l'arresto anomalo. Non l'ho più sperimentato e utilizzerò la stessa soluzione per altre navigazioni per evitare ulteriormente lo stesso errore.
Qualsiasi pensiero è benvenuto!
Cosa causa esattamente l'incidente
Ricorda che qui lavoriamo con lo stesso grafico di navigazione, controller di navigazione e back-stack quando usiamo il metodo Navigation.findNavController
.
Abbiamo sempre lo stesso controller e grafico qui. Quando navigate(R.id.my_next_destination)
viene chiamato grafico e back-stack cambia quasi istantaneamente mentre l'interfaccia utente non è ancora aggiornata. Solo non abbastanza veloce, ma va bene. Dopo che il back-stack è stato modificato, il sistema di navigazione riceve la seconda navigate(R.id.my_next_destination)
chiamata. Poiché il back-stack è cambiato, ora operiamo in relazione al primo frammento nello stack. Il frammento superiore è il frammento verso il quale si naviga utilizzando R.id.my_next_destination
, ma non contiene altre destinazioni successive con ID R.id.my_next_destination
. Quindi ottieni IllegalArgumentException
l'ID di cui il frammento non sa nulla.
Questo errore esatto può essere trovato in NavController.java
method findDestination
.