Fixed
Status Update
Comments
jb...@google.com <jb...@google.com>
te...@gmail.com <te...@gmail.com> #2
It is not possible for the view of the NavHostFragment to be available in the onCreate() of the Activity. In this case, the NavHostFragment lifecycle method follows the Activity lifecycle methods directly therefore, when the activity is on onCreate() so is the NavHostFragment. However, if the Fragment Lifecycle was driven with a LifecycleObserver (https://issuetracker.google.com/issues/127528777 ), onCreate() could be dispatched for a Fragment separately from the onCreate() for an Activity (or a parent Fragment if using a child Fragment). This means that if you were using a LifecycleObserver, it would be possible for the views to be available when onCreate() is dispatched and findNavController() would work in the LifecycleObserver's onCreate().
This is being tracked byhttps://issuetracker.google.com/issues/143145612 .
This is being tracked by
cl...@google.com <cl...@google.com>
cl...@google.com <cl...@google.com> #3
Possible workaround #4: call findNavController in onPostCreate.
te...@gmail.com <te...@gmail.com> #5
#4: Why can't Navigation.findNavController(activity, id) do that?
public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
if (activity instanceof FragmentActivity) {
NavHostFragment navHostFragment = (NavHostFragment)(((FragmentActivity)activity).getSupportFragmentManager().findFragmentById(viewId));
return navHostFragment.getNavController();
}
View view = ActivityCompat.requireViewById(activity, viewId);
NavController navController = findViewNavController(view);
if (navController == null) {
throw new IllegalStateException("Activity " + activity + " does not have a NavController set on " + viewId);
}
return navController;
}
public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
if (activity instanceof FragmentActivity) {
NavHostFragment navHostFragment = (NavHostFragment)(((FragmentActivity)activity).getSupportFragmentManager().findFragmentById(viewId));
return navHostFragment.getNavController();
}
View view = ActivityCompat.requireViewById(activity, viewId);
NavController navController = findViewNavController(view);
if (navController == null) {
throw new IllegalStateException("Activity " + activity + " does not have a NavController set on " + viewId);
}
return navController;
}
pr...@google.com <pr...@google.com> #7
Here the code when using solution #4:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_store, R.id.navigation_library)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
Works perfectly fine :)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_store, R.id.navigation_library)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
Works perfectly fine :)
Description
Version used: 2.6.0
Devices/Android versions reproduced on: every device & tested in above SDK 23
If this is a bug in the library, we would appreciate if you could attach:
- Sample project to trigger the issue.
- A screenrecord or screenshots showing the issue (if UI related).
Issue:
When using navigation component in fragment, the destination fragment's viewModel (which configured savedState & restoreState) is not cleared even though the destination popped from backstack.
For clearing destination's VM, I should call `navController.clearBackStack(destinationId)`.
I know It is intended feature for preserving VM's state for later restore.
However, the problem happens in the situation that the destination fragment has nested fragment and nested fragment has its VM (call nested VM).
Nested VM never cleared when call `navController.clearBackStack(destinationId)` of parent fragment.
Sadly, VM never cleared even though activity is destroyed. (if application not terminated)
I attached sample project and screen record for reproduce.