'How to navigate between two activities using jetpack navigation library
I'm working on a simple app to test out JetPack Navigation in Android. My App have two activities "Activity1" and "Activity2". I'm aware that Jetpack navigation only works for SingleActivity apps but I want to see if there is any solution to my problem. App starts with "Activity1". Below is the navigation xml
<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/mobile_nav"
app:startDestination="@+id/fragmentA1">
<fragment
android:id="@+id/fragmentA1"
android:name="com.example.android.codelabs.navigation.FragmentA1"
android:label="@string/home"
tools:layout="@layout/fragment_a_one">
<action
android:id="@+id/go_to_fragmentA2"
app:destination="@+id/fragmentA2"/>
</fragment>
<fragment
android:id="@+id/fragmentA2"
android:name="com.example.android.codelabs.navigation.FragmentA2"
tools:layout="@layout/fragment_a_two">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="1"/>
<argument
android:name="displayName"
app:argType="string"
android:defaultValue="Hello"/>
<action
android:id="@+id/go_to_fragmentA3"
app:destination="@+id/fragmentA3"/>
</fragment>
<fragment android:id="@+id/fragmentA3"
android:name="com.example.android.codelabs.navigation.FragmentA3"
android:label="fragment_third"
tools:layout="@layout/fragment_a_three">
<action android:id="@+id/go_to_activityB"
app:destination="@id/activityB"/>
</fragment>
<activity android:id="@+id/activityB"
android:name="com.example.android.codelabs.navigation.registration.ActivityB"
android:label="activity_registration_main"
tools:layout="@layout/activity_registration_main">
<argument android:name="firstName"
app:argType="string"/>
</activity>
<fragment android:id="@+id/fragmentB1"
android:name="com.example.android.codelabs.navigation.registration.FragmentB1"
android:label="fragment_step1"
tools:layout="@layout/fragment_b_one">
<argument android:name="firstName"
app:argType="string"/>
</fragment>
<fragment android:id="@+id/fragmentB2"
android:name="com.example.android.codelabs.navigation.registration.FragmentB2"
android:label="fragment_step2"
tools:layout="@layout/fragment_b_two">
<argument android:name="lastName"
app:argType="string"/>
</fragment>
Below is the code from ActivityB
val navController = findNavController(R.id.registration_navHost)
navController.setGraph(R.navigation.mobile_navigation)
navController.navigate(R.id.fragmentB1,safeArgs.toBundle())
Code to get safeArgs in ActivityB
private val safeArgs by navArgs<ActivityBArgs>()
Here are my questions. 1. How can I navigate from ActivityB(FragmentB1) to ActivityA(FragmentA2) Using jetpack Navigation. 2. Is there any way to access the backStack through any Manager Classes in android ?
Why Do I Need Two Activities? FragmentA1,FragmentA2 and FragmentA3 which are part of ActivityA shouldn't have any bottom navigation and drawer layout. Depending on answers selected in these fragments, a bottom navigation and a drawer layout are displayed in ActivityB. On Pressing back button from anywhere on ActivityB, ActivityA should come alive with FragmentA3. Also the toolBar is different for ActivityA and ActivityB
Solution 1:[1]
Despite having two Activities, then again I recommend Single Activity apps. I had some testing to separate the Activity because one had BottomNavigation and one without BottomNavigation (Like your issue here). But I always stuck to navigate between the Activities and the backstack always reset (as far as I test it).
Other solution would be Nested NavigationGraph, but I avoid some nested because I think it'll mingle the navigation. So yeah, I try to find another approach and here's what I test and use now.
Some workaround
Let's make a new scenario. I have 3 page that has BottomNavigation (Dashboard, Search, Profile). Then I have a page that doesn't has BottomNavigation, ex. ProfileDetail that opened from Profile. So in this scenario, I'll create:
- NavigationHostActivity (Activity that has BottomNavigation)
- DashboardFragment (Fragment)
- SearchFragment (Fragment)
- ProfileFragment (Fragment)
- ProfileDetailFragment (Fragment)
I change all my layout became Fragments and when it navigates to any layout, it will check wether they need the BottomNavigation. The basic concept is Show / Hide the BottomNavigation. Here's some example that I use:
NavigationHostActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.bind(
this.findNavController(R.id.navigation_host_fragment),
this.binding.navigationBottomView
)
}
fun bind(navigationController: NavController, bottomNavigationView: BottomNavigationView) {
navigationController.addOnDestinationChangedListener { _, destination, _ ->
this.hideBottomNavigation(bottomNavigationView)
bottomNavigationView.menu.forEach {
if (it.itemId == destination.id) {
this.showBottomNavigation(bottomNavigationView)
}
}
}
}
fun hideBottomNavigation(bottomNavigationView: BottomNavigationView) { bottomNavigationView.visibility = View.GONE }
fun showBottomNavigation(bottomNavigationView: BottomNavigationView) { bottomNavigationView.visibility = View.VISIBLE }
This will check wether the destination of Navigation is the same as menu of your BottomNavigation. If it's one of the BottomNavigation Menu, then it Show the BottomNavigation.
Actually I put bind, show and hide function in NavigationService, so this is roughly what I did. And this was made for easier example. Feel free to tweak it. I also use DataBinding here FYI.
navigation_host_fragment
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation_bottom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF"
app:itemIconSize="22dp"
app:itemIconTint="@color/state_bottom_navigation_view"
app:itemTextColor="@color/state_bottom_navigation_view"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/menu_dashboard" />
<fragment
android:id="@+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/navigation_bottom_view"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
<data>
<variable
name="activity"
type="*.view.NavigationHostActivity" />
</data>
</layout>
menu_dashboard
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/dashboardFragment"
android:title="Dashboard"/>
<item
android:id="@+id/searchFragment"
android:title="Search" />
<item
android:id="@+id/profileFragment"
android:title="Profile" />
</menu>
And that's it, work perfectly for my case. Hope it helps :D
Regards,
Andrea
Solution 2:[2]
It's tricky with activities, but you can achieve the same effect in single-activity application by using children fragments.
- Create two fragments,
FragmentAandFragmentB. Move all UI fromActivityAtoFragmentAand fromActivityBtoFragmentB.ActivityAshould hold aNavHostFragmentonly. RemoveActivityB. - Create main navigation graph containing
FragmentA,FragmentBand connect them. Install the graph toActivityA. - Create another navigation graph, containing
FragmentA1,FragmentA2,FragmentA3and install it toNavHostFragmentdeclared inFragmentA. - Create one more navigation graph with
FragmentB1andFragmentB2and install it toNavHostFragmentdeclared inFragmentB.
That's it. Now when you need to navigate between FragmentA and FragmentB or back, just use navigation controller from parent fragment: parentFragment?.findNavController() or view model from parent fragment (if you are using viewmodels for navigation).
Solution 3:[3]
Activities can now be items within Navigation Graphs and can be navigated to using destinations. Since around Jetpack Navigation 2.3.0? Support is limited though, still room for new feature requests.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Andrea Lk |
| Solution 2 | esentsov |
| Solution 3 | straya |

