タイトルは短すぎて意味が正確ではないかも。
「NavigationUIを使用している場合に、メニューから遷移可能な宛先画面(Destination)をリロードする。」 もし、NavigationUIを使っていないなら、NavController#navigateで遷移すればいいです。
経緯
Android Studio3.5のナビゲーションドロワーアクティビティをベースにActivityを作っているときに、ユーザ操作によって設定を書き換え、それを反映するために画面をリロードしたかった。
だが、NavController#navigateで遷移すると画面(Fragment)のonSaveInstanceStateでViewModelがヌルポになる。ViewModelインスタンスがfinalizeされた?
- メニュー構成は「ホーム」、「子画面」
- 「子画面」が表示されていたらリロード処理(NavController#navigate)する
- リロード後に画面を2回転させるとonSaveInstanceStateでViewModelメンバ変数がnullで死亡
解決
NavControllerをいじってダメだったため、ユーザ操作をエミュレートしてやれば動くと想像 ⇒ \(^o^)/
//MainActivity内に以下のメソッドを作成する。 /** ナビゲーションによって表示されている画面をリロードする */ public void reloadDestination(){ final @NonNull NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); //コントローラ final @Nullable NavDestination currentDestination = navController.getCurrentDestination(); //現在の画面 final @NonNull NavigationView navigationView = findViewById(R.id.nav_view); //メニュー if(currentDestination!=null) { final @Nullable MenuItem item = navigationView.getMenu().findItem(currentDestination.getId()); //MenuItem逆引き if (item != null) { //逆引き成功 NavigationUI.onNavDestinationSelected(item, navController); //navController.navigate(resId); 直接navigateを呼び出すとバグる } } } /** ナビゲーションによって表示されている画面をリロードする * @param matchIDs リロード対象の画面、一致しなければ何もしない */ public void reloadDestination(int... matchIDs){ final @NonNull NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); //コントローラ final @Nullable NavDestination currentDestination = navController.getCurrentDestination(); //現在の画面 final @NonNull NavigationView navigationView = findViewById(R.id.nav_view); //メニュー if(currentDestination!=null) { for (int resId : matchIDs) { if (currentDestination.getId() == resId) { //現在の画面と引数が一致 final @Nullable MenuItem item = navigationView.getMenu().findItem(resId); //MenuItem逆引き if (item != null) { //逆引き成功 NavigationUI.onNavDestinationSelected(item, navController); //navController.navigate(resId); 直接navigateを呼び出すとバグる } } } } }