Search code examples
androidandroid-architecture-navigation

Navigation Component Where to initialize NavController in Fragment


In my MainFragment class, when trying to initialize NavController in the onCreateView, I get a RuntimeException caused by:

IllegalStateException: View android.widget.RelativeLayout{cf3c6de V.E...... ......I. 0,0-0,0 #7f0800d7 app:id/parentLayout} does not have a NavController set.

If the NavController is initialised in the onViewCreated method, it will work just fine. Why is that? I couldn't figure it out from the tutorials / documentation.

fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/parentLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainFragment">

    <Button...>

    <Button...>

    <Button...>

</RelativeLayout>

MainFragment.java

public class MainFragment extends Fragment {

    private NavController navController;
    private Button bViewTransaction, bSendMoney, bViewBalance;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);

        bViewTransaction = view.findViewById(R.id.view_transactions_btn);
        bSendMoney = view.findViewById(R.id.send_money_btn);
        bViewBalance = view.findViewById(R.id.view_balance_btn);

//         IllegalStateException
        navController = Navigation.findNavController(view);

        return view;

    }

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

//         NO problem
//        navController = Navigation.findNavController(view);

        bViewTransaction.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navController.navigate(R.id.action_mainFragment_to_viewTransactionFragment);
            }
        });

        bSendMoney.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navController.navigate(R.id.action_mainFragment_to_chooseRecipientFragment);
            }
        });

        bViewBalance.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navController.navigate(R.id.action_mainFragment_to_viewBalanceFragment);
            }
        });


    }
}

activity_main.xml ,if it is relevant

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"

        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • Your view is not yet attached to your fragment in onCreateView method, thats why you get exception. On the other hand in onViewCreated view is attached to fragment and you can use it. Also in fragments you should be able to use findNavController() without arguments, still, this will also fail if its called before view is created.