Android Studio How to Pass Data With Back Button
Navigating to a destination is done using a NavController
, an object that manages app navigation within a NavHost
. Each NavHost
has its own corresponding NavController
. NavController
provides a few different ways to navigate to a destination, which are further described in the sections below.
To retrieve the NavController
for a fragment, activity, or view, use one of the following methods:
Kotlin:
-
Fragment.findNavController()
-
View.findNavController()
-
Activity.findNavController(viewId: Int)
Java:
-
NavHostFragment.findNavController(Fragment)
-
Navigation.findNavController(Activity, @IdRes int viewId)
-
Navigation.findNavController(View)
After you've retrieved a NavController
, you can call one of the overloads of navigate()
to navigate between destinations. Each overload provides support for various navigation scenarios, as described in the following sections.
Use Safe Args to navigate with type-safety
The recommended way to navigate between destinations is to use the Safe Args Gradle plugin. This plugin generates simple object and builder classes that enable type-safe navigation between destinations. Safe Args is recommended both for navigating as well as passing data between destinations.
To add Safe Args to your project, include the following classpath
in your top level build.gradle
file:
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.3.5" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.3.5" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
You must also apply one of two available plugins.
To generate Java language code suitable for Java or mixed Java and Kotlin modules, add this line to your app or module's build.gradle
file:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Alternatively, to generate Kotlin code suitable for Kotlin-only modules add:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
You must have android.useAndroidX=true
in your gradle.properties
file as per Migrating to AndroidX.
After enabling Safe Args, your generated code contains classes and methods for each action you've defined as well as classes that correspond to each sending and receiving destination.
Safe Args generates a class for each destination where an action originates. The generated class name adds "Directions" to the originating destination class name. For example, if the originating destination is named SpecifyAmountFragment
, the generated class is named SpecifyAmountFragmentDirections
.
The generated class contains a static method for each action defined in the originating destination. This method takes any defined action parameters as arguments and returns a NavDirections
object that you can pass directly to navigate()
.
Safe Args example
As an example, assume we have a navigation graph with a single action that connects two destinations, SpecifyAmountFragment
and ConfirmationFragment
. The ConfirmationFragment
takes a single float
parameter that you provide as part of the action.
Safe Args generates a SpecifyAmountFragmentDirections
class with a single method, actionSpecifyAmountFragmentToConfirmationFragment()
, and an inner class called ActionSpecifyAmountFragmentToConfirmationFragment
. The inner class is derived from NavDirections
and stores the associated action ID and float
parameter. The returned NavDirections
object can then be passed directly to navigate()
, as shown in the following example:
Kotlin
override fun onClick(v: View) { val amount: Float = ... val action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount) v.findNavController().navigate(action) }
Java
@Override public void onClick(View view) { float amount = ...; action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount); Navigation.findNavController(view).navigate(action); }
For more information on passing data between destinations with Safe Args, see Use Safe Args to pass data with type safety.
Navigate using ID
navigate(int)
takes the resource ID of either an action or a destination. The following code snippet shows how to navigate to the ViewTransactionsFragment
:
Kotlin
viewTransactionsButton.setOnClickListener { view -> view.findNavController().navigate(R.id.viewTransactionsAction) }
Java
viewTransactionsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Navigation.findNavController(view).navigate(R.id.viewTransactionsAction); } });
For buttons, there are three variants of Navigation.createNavigateOnClickListener()
. These variants are useful if you're using the Java programming language. If you're using Kotlin, OnClickListener
is a SAM interface, so you can use a trailing lambda. This approach can be shorter and easier to read than calling createNavigateOnClickListener()
directly.
To handle other common UI components, such as the top app bar and bottom navigation, see Update UI components with NavigationUI.
Provide navigation options to actions
When you define an action in the navigation graph, Navigation generates a corresponding NavAction
class, which contains the configurations defined for that action, including the following:
- Destination: The resource ID of the target destination.
- Default arguments: An
android.os.Bundle
containing default values for the target destination, if supplied. - Navigation options: Navigation options, represented as
NavOptions
. This class contains all of the special configuration for transitioning to and back from the target destination, including animation resource configuration, pop behavior, and whether the destination should be launched in single top mode.
Let's take a look at an example graph consisting of two screens along with an action to navigate from one to the other:
<?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/a"> <fragment android:id="@+id/a" android:name="com.example.myapplication.FragmentA" android:label="a" tools:layout="@layout/a"> <action android:id="@+id/action_a_to_b" app:destination="@id/b" app:enterAnim="@anim/nav_default_enter_anim" app:exitAnim="@anim/nav_default_exit_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popExitAnim="@anim/nav_default_pop_exit_anim"/> </fragment> <fragment android:id="@+id/b" android:name="com.example.myapplication.FragmentB" android:label="b" tools:layout="@layout/b"> <action android:id="@+id/action_b_to_a" app:destination="@id/a" app:enterAnim="@anim/nav_default_enter_anim" app:exitAnim="@anim/nav_default_exit_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popExitAnim="@anim/nav_default_pop_exit_anim" app:popUpTo="@+id/a" app:popUpToInclusive="true"/> </fragment> </navigation>
When the navigation graph is inflated, these actions are parsed, and corresponding NavAction
objects are generated with the configurations defined in the graph. For example, action_b_to_a
is defined as navigating from destination b
to destination a
. The action includes animations along with popTo
behavior that removes all destinations from the backstack. All of these settings are captured as NavOptions
and are attached to the NavAction
.
To follow this NavAction
, use NavController.navigate()
, passing the ID of the action, as shown in the following example:
Kotlin
findNavController().navigate(R.id.action_b_to_a)
Java
NavigationHostFragment.findNavController(this).navigate(R.id.action_b_to_a);
Apply NavOptions programmatically
The previous examples show how to specify NavOptions
within the navigation graph XML. However, specific options can vary depending on constraints that are unknown at build time. In such cases, the NavOptions
must be created and set programmatically, as shown in the following example:
Kotlin
findNavController().navigate( R.id.action_fragmentOne_to_fragmentTwo, null, navOptions { // Use the Kotlin DSL for building NavOptions anim { enter = android.R.animator.fade_in exit = android.R.animator.fade_out } } )
Java
NavController navController = NavHostFragment.findNavController(this); navController.navigate( R.id.action_fragmentOne_to_fragmentTwo, null, new NavOptions.Builder() .setEnterAnim(android.R.animator.fade_in) .setExitAnim(android.R.animator.fade_out) .build() );
This example uses an extended form of navigate()
and contains additional Bundle
and NavOptions
arguments. All variants of navigate()
have extended versions that accept a NavOptions
argument.
You can also programmatically apply NavOptions
when navigating to implicit deep links:
Kotlin
findNavController().navigate( deepLinkUri, navOptions { // Use the Kotlin DSL for building NavOptions anim { enter = android.R.animator.fade_in exit = android.R.animator.fade_out } } )
Java
NavController navController = NavHostFragment.findNavController(this); navController.navigate( deepLinkUri, new NavOptions.Builder() .setEnterAnim(android.R.animator.fade_in) .setExitAnim(android.R.animator.fade_out) .build() );
This variant of navigate()
takes a Uri
for the implicit deep link, as well as the NavOptions
instance.
Navigate using DeepLinkRequest
You can use navigate(NavDeepLinkRequest)
to navigate directly to an implicit deep link destination, as shown in the following example:
Kotlin
val request = NavDeepLinkRequest.Builder .fromUri("android-app://androidx.navigation.app/profile".toUri()) .build() findNavController().navigate(request)
Java
NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://androidx.navigation.app/profile")) .build() NavHostFragment.findNavController(this).navigate(request)
In addition to Uri
, NavDeepLinkRequest
also supports deep links with actions and MIME types. To add an action to the request, use fromAction()
or setAction()
. To add a MIME type to a request, use fromMimeType()
or setMimeType()
.
For a NavDeepLinkRequest
to properly match an implicit deep link destination, the URI, action, and MIME type must all match the NavDeepLink
in the destination. URIs must match the pattern, the actions must be an exact match, and the MIME types must be related (e.g. "image/jpg" matches with "image/*").
Unlike navigation using action or destination IDs, you can navigate to any deep link in your graph, regardless of whether the destination is visible. You can navigate to a destination on the current graph or a destination on a completely different graph.
When navigating using NavDeepLinkRequest
, the back stack is not reset. This behavior is unlike other deep link navigation, where the back stack is replaced when navigating. popUpTo
and popUpToInclusive
still remove destinations from the back stack just as though you had navigated using an ID.
Navigation and the back stack
Android maintains a back stack that contains the destinations you've visited. The first destination of your app is placed on the stack when the user opens the app. Each call to the navigate()
method puts another destination on top of the stack. Tapping Up or Back calls the NavController.navigateUp()
and NavController.popBackStack()
methods, respectively, to remove (or pop) the top destination off of the stack.
NavController.popBackStack()
returns a boolean indicating whether it successfully popped back to another destination. The most common case when this returns false
is when you manually pop the start destination of your graph.
When the method returns false
, NavController.getCurrentDestination()
returns null
. You are responsible for either navigating to a new destination or handling the pop by calling finish()
on your Activity, as shown in the following example:
Kotlin
... if (!navController.popBackStack()) { // Call finish() on your Activity finish() }
Java
... if (!navController.popBackStack()) { // Call finish() on your Activity finish(); }
Dialog destinations implement the FloatingWindow
interface, indicating that they overlay other destinations on the back stack. As such, one or more FloatingWindow
destinations can be present only on the top of the navigation back stack. Navigating to a destination that does not implement FloatingWindow
automatically pops all FloatingWindow
destinations off of the top of the stack. This ensures that the current destination is always fully visible above other destinations on the back stack.
As an example, if the back stack consists solely of non-floating destinations, and the user navigates to a Dialog
destination, then the back stack might look similar to figure 1:
If the user then navigates to another Dialog
destination, it is then added to the top of the back stack, as shown in figure 2:
If the user then navigates to a non-floating destination, any FloatingWindow
destinations are first popped from the top of the back stack before navigating to the new destination, as shown in figure 3:
popUpTo and popUpToInclusive
When navigating using an action, you can optionally pop additional destinations off of the back stack. For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn't take users back into the login flow.
To pop destinations when navigating from one destination to another, add an app:popUpTo
attribute to the associated <action>
element. app:popUpTo
tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate()
. The attribute value is the ID of the most recent destination that should remain on the stack.
You can also include app:popUpToInclusive="true"
to indicate that the destination specified in app:popUpTo
should also be removed from the back stack.
popUpTo example: circular logic
Let's say that your app has three destinations—A, B, and C—along with actions that lead from A to B, B to C, and C back to A. The corresponding navigation graph is shown in figure 4:
Figure 4. A circular navigation graph with three destinations: A, B, and C.
With each navigation action, a destination is added to the back stack. If you were to navigate repeatedly through this flow, your back stack would then contain multiple sets of each destination (A, B, C, A, B, C, A, and so on). To avoid this repetition, you can specify app:popUpTo
and app:popUpToInclusive
in the action that takes you from destination C to destination A, as shown in the following example:
<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_c_to_a" app:destination="@id/a" app:popUpTo="@+id/a" app:popUpToInclusive="true"/> </fragment>
After reaching destination C, the back stack contains one instance of each destination (A, B, C). When navigating back to destination A, we also popUpTo
A, which means that we remove B and C from the stack while navigating. With app:popUpToInclusive="true"
, we also pop that first A off of the stack, effectively clearing it. Notice here that if you don't use app:popUpToInclusive
, your back stack would contain two instances of destination A.
popUpToSaveState and restoreSaveState
When you use app:popUpTo
to navigate to a destination, Navigation 2.4.0-alpha01 and higher allow you to optionally save the states of all destinations popped off of the back stack. To enable this option, include app:popUpToSaveState="true"
in the associated <action>
element:
<action android:id="@+id/action_c_to_a" app:destination="@id/a" app:popUpTo="@+id/a" app:popUpToInclusive="true" app:popUpToSaveState="true"/>
When you navigate to a destination, you can also include app:restoreSaveState="true"
to automatically restore the state associated with the destination in app:destination
.
Android Studio How to Pass Data With Back Button
Source: https://developer.android.com/guide/navigation/navigation-navigate
0 Response to "Android Studio How to Pass Data With Back Button"
Postar um comentário