Search code examples
javaandroidandroid-architecture-navigation

Navigation is not working when using ViewModel


I'm using Navigation in android to navigate to the next fragment. The whole app somewhat looks like this.

enter image description here

Navigation XML

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/landingFragment">

    <fragment
        android:id="@+id/landingFragment"
        android:name="com.varun.matic.fragments.LandingFragment"
        android:label="fragment_landing"
        tools:layout="@layout/fragment_landing">
        <action
            android:id="@+id/action_landingFragment_to_signInFragment"
            app:destination="@id/signInFragment" />
        <action
            android:id="@+id/action_landingFragment_to_signUpFragment"
            app:destination="@id/signUpFragment" />
        <action
            android:id="@+id/action_landingFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
    <fragment
        android:id="@+id/signInFragment"
        android:name="com.varun.matic.fragments.SignInFragment"
        android:label="fragment_sign_in"
        tools:layout="@layout/fragment_sign_in">
        <action
            android:id="@+id/action_signInFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
    <fragment
        android:id="@+id/signUpFragment"
        android:name="com.varun.matic.fragments.SignUpFragment"
        android:label="fragment_sign_up"
        tools:layout="@layout/fragment_sign_up">
        <action
            android:id="@+id/action_signUpFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.varun.matic.fragments.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />
</navigation>

Issues

I'm unable to go back to the landing page or move forward to the "homeFragment" when I'm on signInFragment or "signUpFragment"

SignInFragment

public class SignInFragment extends Fragment {


    private View view;

    public SignInFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_sign_in, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        this.view = view;

        if (getActivity() != null) {
            SignInViewModel viewModel = ViewModelProviders.of(this).get(SignInViewModel.class);
            FragmentSignInBinding binding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_sign_in);
            binding.setLifecycleOwner(this);
            binding.setViewModel(viewModel);

            observe(viewModel, binding);
        }
    }

    private void observe(SignInViewModel viewModel, FragmentSignInBinding binding) {

        viewModel.getUser().observe(this, user -> {
            if (TextUtils.isEmpty(Objects.requireNonNull(user).name)) {
                binding.userName.setError("Field can't be empty");
                binding.userName.requestFocus();
            } else if (TextUtils.isEmpty(Objects.requireNonNull(user).password)) {
                binding.userPassword.setError("Field can't be empty");
                binding.userPassword.requestFocus();
            } else {
                logIn(viewModel);
            }
        });
    }

    private void logIn(SignInViewModel viewModel) {
        Boolean CredentialsAreOk = viewModel.checkCredentials();
        if (CredentialsAreOk) {
            Navigation.findNavController(this.view).navigate(R.id.action_signInFragment_to_homeFragment);
        }
    }
}

SignUpFragment

public class SignUpFragment extends Fragment {

    private View view;

    public SignUpFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_sign_up, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        this.view = view;

        if (getActivity() != null) {
            final SignUpViewModel viewModel = ViewModelProviders.of(this).get(SignUpViewModel.class);
            final FragmentSignUpBinding binding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_sign_up);
            binding.setLifecycleOwner(this);
            binding.setViewModel(viewModel);

            observe(viewModel, binding);
        }
    }

    private void observe(SignUpViewModel viewModel, FragmentSignUpBinding binding) {

        viewModel.getUser().observe(this, user -> {
            if (TextUtils.isEmpty(Objects.requireNonNull(user).name)) {
                binding.userName.setError("Field can't be empty");
                binding.userName.requestFocus();
            } else if (TextUtils.isEmpty(Objects.requireNonNull(user).password)) {
                binding.userPassword.setError("Field can't be empty");
                binding.userPassword.requestFocus();
            } else {
                signUp(viewModel, user);
            }
        });
    }

    private void signUp(SignUpViewModel viewModel, User user) {
        Boolean signUpIsSuccessful = viewModel.signUpUser(user.name, user.password);
        if (signUpIsSuccessful) {
            goToHomeFragment();
        }
    }

    private void goToHomeFragment() {
        Navigation.findNavController(view).navigate(R.id.action_signUpFragment_to_homeFragment);
    }
}

I'm not sure why it's happening it is working when I'm direct going to homeFragment from landingFragment by this code

Navigation.findNavController(view).navigate(R.id.action_landingFragment_to_homeFragment);

The back button also behaves how it's supposed to.


Solution

  • You should be doing this

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle 
      savedInstanceState) {
      bindings = DataBindingUtil.inflate(inflater, R.layout.layout, container, false)
      bindings.lifecycleOwner = fragment        
      return binding.root
    }