java.lang.IllegalArgumentException: Navigation action/destination com.sample.store.full:id/action_categoryProductItems2_to_productItem cannot be found from the current destination Destination(id/navigation_home) label=Home class=com.sample.store.main.dashboard.ui.ui.home.mainui.HomeFragment
Ich weiß nicht, was passiert ist, aber es scheint, dass der navController nach “navigation_home” sucht
können Sie die vollständige nav_host.xml-Datei freigeben
– TRK P
9. September 2020 um 6:38 Uhr
@Cyd entfernen Sie diese Zeile ` navController?.navigateUp()` kann Ihr Problem lösen
– Asad Mahmud
9. September 2020 um 11:23 Uhr
Dies ist eher ein Hinweis als eine Antwort. Aber ich hoffe es hilft.
Zusammenfassung: (Wie andere bereits gesagt haben:) Aufeinanderfolgende Aufrufe von Navigationsfunktionen sind der Grund für die meisten dieser Ausnahmen.
Angesichts der Struktur der Android-Komponenten und insbesondere der Funktionsweise von MediatorLiveData möchten Benutzer möglicherweise manchmal Datenknoten in einem einzigen beobachtbaren Datenbehälter (LiveData) zusammenführen.
Wenn eine Beobachtung dieses Mediators mit dynamischen Navigationsfunktionen verknüpft ist, werden zweifellos Fehler auftreten.
Der Grund dafür ist, dass Quellen einen LiveData-Wert so oft ändern können, wie es der Anzahl der Quellen entspricht, die mit dem Mediator verbunden sind.
Das ist eine absolut gute Idee, ABER. Wiederholte Änderungen am NavController führen definitiv zu unerwünschten Ergebnissen.
Dies kann beinhalten:
Den backStack zweimal knallen lassen.
Gehen Sie zweimal hintereinander von A -> B und geben Sie eine Ausnahme von A nicht gefunden
das zweite Mal.
Dies ist ein großes Testproblem, insbesondere da die Ausgabe eines Fragments zu den darunter liegenden Stapeln kaskadieren kann, und wenn daher in einem Fragment eine Ausnahme von „Direction not found“ auftreten kann, kann der wahre Schuldige auf dem Fragment zuoberst des Gebenden gefunden werden die Ausnahme.
In Wirklichkeit wäre dies leicht zu lösen, indem ein selbstabbrechender Thread-Executor erstellt wird scheduled.cancel(true); mit einer Verzögerungstoleranz für die mediatorLiveData selbst (genauer gesagt die onChange, nicht die setValue(), da eifrige innere Zustandsaktualisierungen der gesamte und einzige Zweck/Witz des Mediators IMHO sind (sorry, kein postValue() erlaubt!)).
Ganz zu schweigen davon, dass der Mediator selbst eine unvollständige Komponente ist …
Ein weiterer einfacherer Ansatz besteht darin, sicherzustellen, dass onChange-Aufrufe von MutableLiveData nur dann ausgeführt werden, wenn !Object::Equals, und wiederholte Aufrufe von onChange() zu verhindern, was immer noch ein Beweis für die Unvollständigkeit von MediatorLiveData/LiveData ist. (Seien Sie nur äußerst vorsichtig mit Listen)
Vermeiden Sie um jeden Preis aufeinanderfolgende Aufrufe an einen NavController, und wenn Sie es irgendwie MÜSSEN, dann ist ein verzögertes Runnable möglicherweise Ihre einzige Möglichkeit, dies zu erreichen.
danke für den Hinweis. Ich habe einen Flow für Navigationsänderungen angehört und ihn mehrmals abonniert, als ich anfing, in Fragments onViewCreated (das mehrfach aufgerufen wird) zu lauschen.
– cwiesner
3. März um 10:48 Uhr
Erstens sollten Sie nicht bestehen requireView() wenn Sie versuchen, Ihren Nav-Controller abzurufen – navController = Navigation.findNavController(requireView()). Sie sollten die eigentliche Instanz des Navigationshostfragments übergeben.
Zweitens wird das Problem dadurch verursacht, dass Sie versuchen, einen Navigationspfad von B -> C aufzurufen, wenn Sie sich auf Fragment A befinden.
Ihr Richtungspfad ist von B -> C
val action = CategoryProductItemsDirections.actionCategoryProductItems2ToProductItem(null, it)
Aber Sie navigieren zuerst nach oben, sodass Sie sich jetzt tatsächlich auf Fragment A befinden, wenn Sie versuchen, die Navigation auszuführen:
Beim Umgang mit verschachtelten Fragmenten wie einem ViewPager können Sie leicht den Fehler machen, von einer verschachtelten Seite zu einem anderen Fragment zu navigieren, obwohl die Navigation tatsächlich vom ViewPager-Fragment zum Zielfragment erfolgen muss.
– Jeffrey
23. Juli 2021 um 0:47 Uhr
Interessanter Kommentar, kaufen Sie nicht sicher, welche Relevanz ein Ansichtspager für diesen Beitrag / diese Frage hat? Es wird nicht erwähnt, dass ein View-Pager verwendet wird
– Indiana
24. Juli 2021 um 5:53 Uhr
Ihre Antwort hat mir geholfen, das Problem zu lösen, das ich im Kommentar erwähnt habe. Das heißt, Sie versuchen, von einem Ziel aus zu navigieren, an dem Sie sich gerade nicht befinden.
– Jeffrey
25. Juli 2021 um 3:04 Uhr
vishnu benny
Ich habe eine Erweiterungsfunktion erstellt, um die Möglichkeit zu prüfen, eine Aktion vom aktuellen Ziel aus zu starten.
fun NavController.navigateSafe(@IdRes resId: Int, args: Bundle? = null) {
val destinationId = currentDestination?.getAction(resId)?.destinationId.orEmpty()
currentDestination?.let { node ->
val currentNode = when (node) {
is NavGraph -> node
else -> node.parent
}
if (destinationId != 0) {
currentNode?.findNode(destinationId)?.let { navigate(resId, args) }
}
}}
Und die orEmpty() Teil ist Verlängerung vorbei Int? folgendermaßen:
fun Int?.orEmpty(default: Int = 0): Int {
return this ?: default
}
val destinationId = currentDestination?.getAction(resId)?.destinationId.orEmpty() In dieser Zeile ist das letzte .orEmpty() rot. Ich weiß nicht warum. if (destinationId != EMPTY_INT) { currentNode?.findNode(destinationId)?.let { navigation(resId, args) } } und in dieser Bedingung ist EMPTY_INT rot, welcher Wert dort geprüft wird. führe mich
– Syed Rafaqat Hussain
13. August 2021 um 6:10 Uhr
@SyedRafaqatHussain sieht so aus, als wäre .orEmpty() eine Erweiterung, die den int-Wert auf destinationId anwendet. Sie können destinationId als nullfähige Eigenschaft ohne diesen Erweiterungsaufruf verwenden und einfach die Prüfung in if (destinationId != null) ändern.
– Sviatoslav Zaitsev
17. Februar um 22:09 Uhr
sehr gute Lösung.
– Luis Alegria
27. April um 19:49 Uhr
Aber wenn Sie eine ZielresId anstelle einer AktionsresId übergeben, funktioniert diese Logik nicht, weil currentDestination?.getAction(resId) gibt null zurück.
– Shefchenko
17. Mai um 15:02 Uhr
Homayoon Ahmadi
Hier ist die Java-Version der NavigationUtils-Klasse für eine sichere Navigation:
public abstract class NavigationUtils {
/**
* This function will check navigation safety before starting navigation using direction
*
* @param navController NavController instance
* @param direction navigation operation
*/
public static void navigateSafe(NavController navController, NavDirections direction) {
NavDestination currentDestination = navController.getCurrentDestination();
if (currentDestination != null) {
NavAction navAction = currentDestination.getAction(direction.getActionId());
if (navAction != null) {
int destinationId = orEmpty(navAction.getDestinationId());
NavGraph currentNode;
if (currentDestination instanceof NavGraph)
currentNode = (NavGraph) currentDestination;
else
currentNode = currentDestination.getParent();
if (destinationId != 0 && currentNode != null && currentNode.findNode(destinationId) != null) {
navController.navigate(direction);
}
}
}
}
/**
* This function will check navigation safety before starting navigation using resId and args bundle
*
* @param navController NavController instance
* @param resId destination resource id
* @param args bundle args
*/
public static void navigateSafe(NavController navController, @IdRes int resId, Bundle args) {
NavDestination currentDestination = navController.getCurrentDestination();
if (currentDestination != null) {
NavAction navAction = currentDestination.getAction(resId);
if (navAction != null) {
int destinationId = orEmpty(navAction.getDestinationId());
NavGraph currentNode;
if (currentDestination instanceof NavGraph)
currentNode = (NavGraph) currentDestination;
else
currentNode = currentDestination.getParent();
if (destinationId != 0 && currentNode != null && currentNode.findNode(destinationId) != null) {
navController.navigate(resId, args);
}
}
}
}
private static int orEmpty(Integer value) {
return value == null ? 0 : value;
}
}
Diese Art von Fehler tritt meistens in einer Liste von Elementen auf und das Klicken auf ein Element löst die Navigation aus.
Ich habe mit diesem Code gelöst, Beim Elementklick vor dem Aufruf der Navigationsfunktion überprüfe ich, ob das aktuelle Ziel das beabsichtigte ist wie,
val currentDestinationIsHome = this.findNavController().currentDestination == this.findNavController().findDestination(R.id.nav_home)
val currentDestinationIsDetail = this.findNavController().currentDestination == this.findNavController().findDestination(R.id.nav_detail)
if(currentDestinationIsHome && !currentDestinationIsDetail){
....
// perform navigation
}
Dadurch wird sichergestellt, dass die Navigation nur durchgeführt wird, wenn sich die Ziele in einem legalen Zustand befinden. [No IllegalStateException … :)) ]
Gobinath Nataraj
//Überprüfen Sie, ob das aktuelle Fragment ein ereignisgesteuertes Fragment ist, indem Sie die ID übergeben
fun Fragment.findNavControllerSafely(id: Int): NavController? {
return if (findNavController().currentDestination?.id == id) {
findNavController()
} else {
null
}
}
//In Fragment implementieren, wo Sie die Navigation aufrufen
<action
android:id="@+id/action_categoryProductItems2_to_productItem"
app:destination="@id/productItem"
app:enterAnim="@anim/enter_from_right"
app:exitAnim="@anim/exit_to_right"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_fade_exit"
app:popUpToInclusive="true" /* If true then also remove the destination from stack while popup */
app:popUpTo="@id/navigation_home"/> /*The fragment where to land again from destination*/
14362100cookie-checkNavigationskomponente Kotlin – vom aktuellen Ziel aus nicht auffindbaryes
können Sie die vollständige nav_host.xml-Datei freigeben
– TRK P
9. September 2020 um 6:38 Uhr
@Cyd entfernen Sie diese Zeile ` navController?.navigateUp()` kann Ihr Problem lösen
– Asad Mahmud
9. September 2020 um 11:23 Uhr