1

Hello i am developing one application and i am stuck on navigation in Navigation View.

Example I have activity and inside i have define navigation host controller like below

    setSupportActionBar(mMainToolbar);

    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.homeFragment, R.id.questionBankFragment,
            R.id.testFragment, R.id.dailyHuntFragment,
            R.id.liveClassesFragment)
            .setOpenableLayout(mMainDrawerLayout)
            .build();

    View mNavigationViewHeaderView = mNavigationView.getHeaderView(0);

    mNavHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);

    NavigationUI.setupActionBarWithNavController(this, mNavController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(mNavigationView, mNavController);

    NavigationUI.setupWithNavController(mMainToolbar, mNavController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(mBottomNavigationView, mNavController);

    mNavController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        switch (destination.getId()) {

            case R.id.homeFragment:
            case R.id.questionBankFragment:
                mMainToolbar.setVisibility(View.VISIBLE);
                mBottomNavigationView.setVisibility(View.VISIBLE);
                setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
                setDrawerLocked(false);
                break;


            case R.id.welcomeFragment:
            case R.id.loginFragment:
                mMainToolbar.setVisibility(View.GONE);
                mBottomNavigationView.setVisibility(View.GONE);
                setStatusBarColor(Color.WHITE);
                setDrawerLocked(true);
                break;

        
            case R.id.customModuleFragment:
            case R.id.createCustomModuleOneFragment:
            case R.id.createCustomModuleTwoFragment:
                mBottomNavigationView.setVisibility(View.GONE);
                setDrawerLocked(true);
                break;
            case R.id.logoutFragment:

                new AppSharedPreference(MainActivity.this).clearAllData();

                Intent intent = new Intent(getApplicationContext(), UserAuthanticationActivity.class);
                startActivity(intent);
                finish();
                break;

        }
    });

It is working fine. but now i have to handle navigation on back stack that i not able to understand.

My Question is suppose i am bottom navigation There are 4 Menu. Home, Hunting , Qbank, Exam.

I am selected Qbank. Qbank have 5 fragments A, B, C, D, E. now i have started traverse Fragment A -> B B -> C C -> D

and now i have choice where i have to navigate Back to Direct A like . Current position is D

D - > A

but how i can get back to A and clear stack that i traverse A -> B -> C -> D i want clear this and it's like i want to start again with A.

How I can make possible with Jetpack Navigation Component.

i tried direct navigation or popback stack navigation but it is not work it is gives me error like if i directly navigato to

java.lang.IllegalStateException: View androidx.core.widget.NestedScrollView{98060fe VFED..... ......ID 0,0-0,0} does not have a NavController set
        at androidx.navigation.Navigation.findNavController(Navigation.java:84)
        at app.technotech.koncpt.McqTestFragment$2.onClick(McqTestFragment.java:232)
        at android.view.View.performClick(View.java:7201)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
        at android.view.View.performClickInternal(View.java:7170)
        at android.view.View.access$3500(View.java:806)
        at android.view.View$PerformClick.run(View.java:27562)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

I don't have any idea how i can handle this navigation.Pleas help to fix this my solution

Thanks in advance.

Vasudev Vyas
  • 726
  • 1
  • 10
  • 28

3 Answers3

0

You can check the current navigation destination and pop inclusive if that's your start or desired destination

    if (navController.currentDestination.id == navController.graph.YOUR_PREFERED_DESTIONATION) {
    
            navController.popBackStack(
                navController.graph.YOUR_PREFERED_DESTIONATION, true
            )
    }else {
   navController.navigate(R.id.other_destination)
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
0

Use popUpTo to remove instances of previous Fragment from backstack and use popUpToInclusive to remove first instance of A Fragment otherwise you will have two instances of A Fragment in your stack:

A demo code from Android official documention:

Navigation Graph XML View:

<fragment
android:id="@+id/c"
android:name="com.example.myapplication.C"
android:label="fragment_c"
tools:layout="@layout/fragment_c">

<action
    android:id="@+id/action_d_to_a"
    app:destination="@id/a"
    app:popUpTo="@+id/a"
    app:popUpToInclusive="true"/>
Hamza Israr
  • 411
  • 2
  • 7
0

You should use different navigation graph for each bottom navigation item.

So that each bottom menu item would have its own graph with their own starting destinations. So following this navigation path

A -> B B -> C C -> D and adding following code-

<action
    android:id="@+id/action_d_to_a"
    app:destination="@id/a"
    app:popUpTo="@+id/a"
    app:popUpToInclusive="true"/>

you can pop up to fragment A which will be a starting destination of bottom menu item and you will not get error about NavController destination.

I try to explain further with following example and code-

We have three menu item i.e. Dashboard, Find and options, in main activity I will use following code to setup bottom navigation-

private void setupBottomNavigation() {
        BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav_view);
        bottomNavigationView.setItemIconTintList(null);

        List<Integer> navGraphList = new ArrayList<>();
        navGraphList.add(R.navigation.dashboard_navigation);
        navGraphList.add(R.navigation.find_navigation);
        navGraphList.add(R.navigation.options_navigation);

        LiveData<NavController> navControllerLiveData = new NavigationExtensions().setupWithNavController(
                bottomNavigationView
                , navGraphList
                , getSupportFragmentManager()
                , R.id.fragment_container, getIntent()
        );
        currentNavController = navControllerLiveData;
    }

R.navigation.dashboard_navigation, R.navigation.find_navigation & R.navigation.options_navigation will be navigation files as following-

enter image description here

dashboard_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/dashboard_navigation"
    app:startDestination="@id/dashboardFragment">

    <fragment
        android:id="@+id/dashboardFragment"
        android:name="your.package.DashboardFragment"
        android:label=""
        tools:layout="@layout/fragment_dashboard" >

    </fragment>

    <fragment
        //add other fragment to this graph

    </fragment>

<navigation>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
    android:id="@+id/coordinatorLayout_main"
    android:background="?android:attr/colorBackground"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="?attr/actionBarSize" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        app:itemTextColor="@drawable/bottom_nav_selector"
        android:id="@+id/bottom_nav_view"
        android:layout_width="match_parent"
        app:itemRippleColor="?colorPrimary"
        app:labelVisibilityMode="labeled"
        android:layout_height="?attr/actionBarSize"
        android:layout_gravity="bottom"
        app:menu="@menu/bottom_nav_menu"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

bottom_nav_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/dashboard_navigation"
        android:icon="@drawable/dashboard_icon_selector"
        android:title="@string/dashboardTitle" />

    <item
        android:id="@+id/find_navigation"
        android:icon="@drawable/find_icon_selector"
        android:title="@string/findTitle" />

    <item
        android:id="@+id/options_navigation"
        android:icon="@drawable/setting_icon_selector"
        android:title="@string/optionTitle" />

</menu>

Make sure menu item id match with id of navigation graph. As check for Dashboard, I have used menu item id as android:id="@+id/dashboard_navigation" which is the same id, for dashboard_navigation.xml graph

enter image description here

You must be also using Navigation Extension (In Kotlin) provided by google itself.

To get more information on using multiple nav-graghs, click here

If you want to understand how to use Navigatin Extension File with your java code, please check my answer here.

Happy Coding !

Nikhil Sharma
  • 897
  • 1
  • 4
  • 18
  • if i will create each navigation graph for bottom navigation then i have create individual navigation host fragment for each graph? – Vasudev Vyas Nov 03 '20 at 06:14
  • @VasudevVyas host fragment will be placed inside main activity and fragment inside can be changes via navigation graph, I have uploaded main activity and menu xml in answer please check. – Nikhil Sharma Nov 03 '20 at 06:26
  • ` app:startDestination="fragmentid"` flag in nav-graph will decide which fragment will be starting fragment of that nav-graph. Usually we attach fragment id with bottom nav menu item but with multiple nav-graph we are attaching nav-graphs via their id to bottom nav menu. – Nikhil Sharma Nov 03 '20 at 06:29
  • unable to get navigation click listener... don't know whats wrong with it – Vasudev Vyas Nov 05 '20 at 10:36