Study Conditional Navigation - problem of incompatible types and initial navigation

There are 2 problems encountered when I study the conditional navigation through the Android developer site: Incompatible types (super Object) and failing to navigate to the login fragment. I write down here to remind myself and hopefully, may help other beginners of Android app development  with the same problems.

Error: Incompatible types (super Object)

Following the example code in Android developer official site [1] , we check the content stored in SavedStateHandle in the onCreate() method of Profile Fragment.
NavBackStackEntry navBackStackEntry = navController.getCurrentBackStackEntry();
SavedStateHandle savedStateHandle = navBackStackEntry.getSavedStateHandle();
savedStateHandle.getLiveData(LoginFragment.LOGIN_SUCCESSFUL)
                .observe(navBackStackEntry, (Observer<Boolean>) success -> {
                    if (!success) {
                        int startDestination = navController.getGraph().getStartDestination();
                        NavOptions navOptions = new NavOptions.Builder()
                                .setPopUpTo(startDestination, false)
                                .build();
                        navController.navigate(startDestination, null, navOptions);
                    }
                });

However, Android Studio interprets the instantiation of Observer as an error. When you compile, it gives an incompatible error.
error: incompatible types: Observer<Boolean> cannot be converted to Observer<? super Object>
                .observe(navBackStackEntry, (Observer<Boolean>) success -> {
                                            ^

The solution is to use getLiveData(String key, T initialValue) method, as shown below. 
savedStateHandle.getLiveData(LoginFragment.LOGIN_SUCCESSFUL, true)
                .observe(navBackStackEntry, (Observer<Boolean>) success -> {
………

I guess the compile does not know the object type stored with the key LoginFragment.LOGIN_SCCESSFUL at this moment. By adding the initial value, the compiler now can compare the object type of initial value and that you declared in Observer<>.

Fail to navigate to the LoginFragment

Whether Profile fragment will navigate to LoginFragment or not depends on the availability of User. 
The determination and action of navigation is implemented in the ViewModel. If we do not assign anything to the User variable of ViewModel in MainFragment before navigating to Profile Fragment, it will fail to navigate to the LoginFragment. The onChanged method of Observer class is not invoked because there is no change on the variable.
public class ProfileFragment extends Fragment {
    private UserViewModel userViewModel;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);
        final NavController navController = Navigation.findNavController(view);
        userViewModel.user.observe(getViewLifecycleOwner(), (Observer<User>) user -> {
            if (user != null) {
                showWelcomeMessage();
            } else {
                navController.navigate(R.id.login_fragment);
            }
        });
    }
………
}

Therefore, before navigate to Profile Fragment. We need to assign null to the variable User of ViewModel
public class MainFragment extends Fragment {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceBundle){
        ……
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);
        Button viewProfileButton = view.findViewById(R.id.view_profile_button);
        viewProfileButton.setOnClickListener((View.OnClickListener) v->{
            userViewModel.setUser(null);
            Navigation.findNavController(v).navigate(R.id.action_mainFragment_to_profileFragment);
        });

    }
    ……
}

留言

此網誌的熱門文章

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library