Is it possible to set startDestination conditionally using Android Navigation Architecture Component(Android Jetpack)?

前端 未结 5 824
难免孤独
难免孤独 2020-12-02 11:53

I am using Navigation from Android Jetpack to navigate between screens. Now I want to set startDestination dynamically.

I have an Activity named MainActivity And t

相关标签:
5条回答
  • 2020-12-02 12:34

    Finally, I got a solution to my query...

    Put below code in onCreate() method of Activity.

    Kotlin code

    val navHostFragment = home_nav_fragment as NavHostFragment
    val inflater = navHostFragment.navController.navInflater
    val graph = inflater.inflate(R.navigation.nav_main)
    graph.setDefaultArguments(intent.extras)
    graph.startDestination = R.id.fragment1
    //or
    //graph.startDestination = R.id.fragment2
    
    navHostFragment.navController.graph = graph
    

    Java code

    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.home_nav_fragment);  // Hostfragment
    NavInflater inflater = navHostFragment.getNavController().getNavInflater();
    NavGraph graph = inflater.inflate(R.navigation.nav_main);
    graph.setDefaultArguments(getIntent().getExtras());
    graph.setStartDestination(R.id.fragment1);
    
    navHostFragment.getNavController().setGraph(graph);
    navHostFragment.getNavController().getGraph().setDefaultArguments(getIntent().getExtras());
    
    
    NavigationView navigationView = findViewById(R.id.navigationView);
    NavigationUI.setupWithNavController(navigationView, navHostFragment.getNavController());
    

    Additional Info

    As @artnest suggested, remove the app:navGraph attribute from the layout. It would look something like this after removal

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout 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">
    
        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/home_nav_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true" />
    
    </FrameLayout>
    

    In the case of a fragment tag used instead of FragmentContainerView, the above changes remain the same

    0 讨论(0)
  • You can set your starting destination programmatically, however, most of the time your starting logic will consult some remote endpoint. If you don't show anything on screen your UI will look bad.

    What I do is always show a Splash screen. It will determine which is the next Screen to Show.

    For instance, in the picture above you can ask in the Splash Screen State if there is a saved LoginToken. In case it's empty then you navigate to the Login Screen.

    Once the Login Screen is done, then you analyze the result save the Token and navigate to your Next Fragment Home Screen.

    When the Back Button is Pressed in the Home Screen, you will send back a Result message to the Splash Screen that indicates it to finish the App.

    To pop 1 Fragment back and navigate to another you can use the following code:

    val nextDestination = if (loginSuccess) {
            R.id.action_Dashboard
        } else {
            R.id.action_NotAuthorized
        }
    
    val options = NavOptions.Builder()
            .setPopUpTo(R.id.loginParentFragment, true)
            .build()
    
    findNavController().navigate(nextDestination, null, options)
    
    0 讨论(0)
  • 2020-12-02 12:38

    Some of the APIs have changed, are unavailable or are not necessary since Akash's answer. It's a bit simpler now.

    MainActivity.java:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    
      NavHostFragment navHost = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_main_nav_host);
      NavController navController = navHost.getNavController();
    
      NavInflater navInflater = navController.getNavInflater();
      NavGraph graph = navInflater.inflate(R.navigation.navigation_main);
    
      if (false) {
        graph.setStartDestination(R.id.oneFragment);
      } else {
        graph.setStartDestination(R.id.twoFragment);
      }
    
      navController.setGraph(graph);
    }
    

    activity_main.xml:

    <?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">
    
      <!-- Following line omitted inside <fragment> -->
      <!-- app:navGraph="@navigation/navigation_main" -->
      <fragment
        android:id="@+id/fragment_main_nav_host"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
      />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    navigation_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Following line omitted inside <navigation>-->
    <!-- app:startDestination="@id/oneFragment" -->
    <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/navigation_main"
      >
    
      <fragment
        android:id="@+id/oneFragment"
        android:name="com.apponymous.apponymous.OneFragment"
        android:label="fragment_one"
        tools:layout="@layout/fragment_one"/>
      <fragment
        android:id="@+id/twoFragment"
        android:name="com.apponymous.apponymous.TwoFragment"
        android:label="fragment_two"
        tools:layout="@layout/fragment_two"/>
    </navigation>
    
    0 讨论(0)
  • 2020-12-02 12:51

    this is not an answer but Just a replication of @Akash Patel answer in more clean and clear way

    // in your MainActivity
    navController = findNavController(R.id.nav_host_fragment)
    val graph = navController.navInflater.inflate(R.navigation.nav_graph)
    if (Authentication.checkUserLoggedIn()) {
          graph.startDestination = R.id.homeFragment
    } else {
          graph.startDestination = R.id.loginFragment
    }
    navController.graph = graph
    
    0 讨论(0)
  • 2020-12-02 12:52

    This can be done with navigation action. Because fragmentA is your start destination, so define an action in fragmentA.

    Note these two fields: app:popUpToInclusive="true" app:popUpTo="@id/fragmentA"

    <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/lrf_navigation"
       app:startDestination="@id/fragmentA">
    
       <fragment
           android:id="@+id/fragmentA"
           android:name="com.mindinventory.FragmentA"
           android:label="fragment_a"
           tools:layout="@layout/fragment_a">
    
        <action android:id="@+id/action_a_to_b"
                app:destination="@id/fragmentB"
                app:popUpToInclusive="true"
                app:popUpTo="@id/fragmentA"/>
       <fragment>
    
       <fragment
           android:id="@+id/fragmentB"
           android:name="com.mindinventory.FragmentB"
           android:label="fragment_b"
           tools:layout="@layout/fragment_b"/>
    </navigation>
    

    When your MainActivity started, just do the navigation with action id, it will remove fragmentA in the stack, and jump to fragmentB. Seemingly, fragmentB is your start destination.

    if(!isAllSetUp)
    {
      // FragmentB
      navController.navigate(R.id.action_a_to_b)
    }
    
    0 讨论(0)
提交回复
热议问题