TL; DRnavigate
通話をtry-catch
(簡単な方法で)ラップするかnavigate
、短期間にの通話が1つだけになるようにします。この問題はおそらく解消されません。より大きなコードスニペットをアプリにコピーして試してください。
こんにちは。上記のいくつかの有用な回答に基づいて、拡張可能な私のソリューションを共有したいと思います。
これが私のアプリケーションでこのクラッシュを引き起こしたコードです:
@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);
}
バグを簡単に再現する方法は、アイテムのリストを複数の指でタップして、各アイテムのクリックが新しい画面へのナビゲーションで解決されるようにすることです(基本的に、メモした人と同じ-非常に短時間で2回以上のクリック) )。きがついた:
- 最初の
navigate
呼び出しは常に正常に機能します。
- 2番目以降のすべての
navigate
メソッドの呼び出しは、で解決されIllegalArgumentException
ます。
私の観点からは、この状況は非常に頻繁に発生する可能性があります。コードの繰り返しは悪い習慣であり、次の解決策について私が考えた1つの影響点を持つことは常に良いことなので、
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.");
}
}
}
したがって、上記のコードはこれから1行だけ変更されます。
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
これに:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
それも少し短くなりました。コードは、クラッシュが発生した正確な場所でテストされました。もう経験はありませんでした。他のナビゲーションにも同じソリューションを使用して、同じ間違いをさらに回避します。
どんな考えでも大歓迎です!
クラッシュの正確な原因
ここでは、methodを使用するときに、同じナビゲーショングラフ、ナビゲーションコントローラー、バックスタックを操作することを覚えておいてくださいNavigation.findNavController
。
ここでは常に同じコントローラーとグラフを取得します。場合はnavigate(R.id.my_next_destination)
、グラフとバックスタックが変わると呼ばれ、ほぼ瞬時に UIがまだ更新されていない間。十分な速度ではありませんが、それで問題ありません。バックスタックが変更された後、ナビゲーションシステムは2番目のnavigate(R.id.my_next_destination)
呼び出しを受信します。バックスタックが変更されたので、スタックの一番上のフラグメントに対して動作するようになりました。一番上のフラグメントは、を使用して移動するフラグメントですが、R.id.my_next_destination
次のIDの宛先は含まれていませんR.id.my_next_destination
。したがってIllegalArgumentException
、フラグメントが何も知らないため、ID が取得されます。
この正確なエラーはNavController.java
methodにありfindDestination
ます。