1, Navigation introduction
1.1 Background of Navigation birth
The UI architecture mode of nesting multiple fragments with a single Activity has been accepted by most Android engineers. However, managing fragments has always been a hassle, and engineers need to manage switching between fragments through FragmentManager and FragmentTransaction.
In Android, page switching and management include application Appbar management, Fragment animation switching, parameter transfer between fragments and so on. Also, the pure code approach is not particularly user-friendly, and Appbar can be confusing to manage and use. Therefore, Jetpack provides a component called Navigation that is designed to make it easy for developers to manage Fragment pages and appbars.
Compared to FragmentManager and FragmentTransaction, using a Navigation component has the following advantages:
- Visual page navigation diagram, convenient for us to clarify the relationship between pages
- Navigate between pages through destinations and actions
- Easy to add page switch animation
- Type-safe parameter passing between pages
- Unified management of menu/bottom Navigation/drawer blue menu Navigation via Navigation UI class
- Support DeepLink DeepLink
1.2 Navigation elements
Before formally learning Navigation components, we need to have a simple understanding of the main elements of Navigation, which is mainly composed of three parts.
- Navigation Graph: An XML resource that contains all Navigation and page relationships.
- NavHostFragment: A special Fragment used to hold navigational content in containers.
- NavController: Manages the navigation objects of applications and performs operations such as jumping between fragments.
Second, Navigation use
2.1 Adding a Dependency
First, create a new Android project and introduce the following dependency script in build.gradle.
dependencies {
def nav_version = "2.3.2"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
Copy the code
2.2 Creating a Navigation Diagram
In the [Project] window, right-click in the res directory and select [New] -> [Android Resource File] to create the New Resource File dialog box, as shown below.In the popup interface, you can enter File name freely, select Navigation with Resource Type, and then click OK.After clicking OK, the navigation directory will be created under the RES directory, along with the navigation file nav_graph.xml.
2.3 Navigation graph
Open the nav_graph. XML file, and you can see that there is no current content in the Design interface. You can click the “New Destination” icon and then click “Create New Destination” to quickly Create a New Fragment. The FragmentA, FragmentB, and FragmentC fragments are created.
Click on a page and a dot will appear on the right. Drag the dot to the right of the page. For example, set the link to FragmentA -> FragmentB -> FragmentC.Then we switch to the Code panel and see the generated Code shown below.
<? 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/fragmentA">
<fragment
android:id="@+id/fragmentA"
android:name="com.example.testnavigation.FragmentA"
android:label="fragment_a"
tools:layout="@layout/fragment_a" >
<action
android:id="@+id/action_fragmentA_to_fragmentB"
app:destination="@id/fragmentB" />
</fragment>
<fragment
android:id="@+id/fragmentB"
android:name="com.example.testnavigation.FragmentB"
android:label="fragment_b"
tools:layout="@layout/fragment_b" >
<action
android:id="@+id/action_fragmentB_to_fragmentC"
app:destination="@id/fragmentC" />
</fragment>
<fragment
android:id="@+id/fragmentC"
android:name="com.example.testnavigation.FragmentC"
android:label="fragment_c"
tools:layout="@layout/fragment_c" />
</navigation>
Copy the code
Several tags are used in the generated code above, with the following meanings.
- Navigation: The root tag that specifies the default startup page via the startDestination configuration.
- Fragment: The fragment tag represents a fragment view.
- Action: The Action tag defines the behavior of the page to jump to, the Destination tag defines the target page to jump to, and can also define the jump animation.
2.4 NavHostFragment
A Fragment needs an Activity container to function properly. NavHostFragment is the container that holds navigation content, and it needs to be bound to an Activity.
<? 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/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code
Among them, the android: name = “androidx. Navigation. Fragments. NavHostFragment” the role of the line of code is to tell the android system this is a special fragments. And if app:defaultNavHost=”true” is true, the Fragment will be returned automatically.
- Android: name Specifies NavHostFragment
- App: navGraph specifies the navigation view, which is built nav_graph.xml
- App :defaultNavHost=true, can intercept the system return key, can be taken as a default to achieve the return key function fragment.
Then we run the program and see that the FragmentA page is displayed by default. This is because the MainActivity layout file has NavHostFragment configured and assigned the FragmentA page to display by default.
2.5 NavController
Navcontrollers are used to manage jumps between fragments. Each NavHost has its own NavController. FindNavController can be used to obtain the NavController and then navigate between pages using NavController’s navigate or navigateUp methods.
Open the Fragmenta.java file and add the following code to the onViewCreated lifecycle method.
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
Button btnB = view.findViewById(R.id.btn_b);
btnB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB); }});return view;
}
Copy the code
Run the above code, and then click FragmentA page button, the system will through Navigation. FindNavController (v) navigate Navigation to FragmentB () method.
2.6 Adding Animations
When jumping between fragments, you can also animate the jump. Open the Design option of the nav_graph.xml file, and in the Animations section of the Attributes panel, click the drop-down arrow next to the animation you want to add. Developers can choose from the following types, as shown in the Animations section below.The Attributes panel refers to the following Attributes.
- EnterAnim: Animation of the target page when jumping
- ExitAnim: Animation of the original page when jumping
- PopEnterAnim: Target page animation for rollback
- PopExitAnim: Original page animation at rollback time
Then, open the Code panel and generate the following Code.
<fragment
android:id="@+id/fragmentA"
android:name="com.xzh.jetpack.FragmentA"
android:label="fragment_a"
tools:layout="@layout/fragment_a" >
<action
android:id="@+id/action_fragmentA_to_fragmentB"
app:destination="@id/fragmentB"
app:enterAnim="@android:anim/slide_in_left"
app:exitAnim="@android:anim/slide_out_right"
app:popEnterAnim="@anim/fragment_fade_enter"
app:popExitAnim="@anim/fragment_fade_exit" />
</fragment>
Copy the code
Parameter transfer
In Android, it is recommended to pass as little data as possible between pages, because the total space available to store all the states on Android is limited. If you need to pass a lot of data, you can use the ViewModel.
Fragment switching is often accompanied by passing parameters. In order to coordinate with the Navigation component to pass parameters when switching fragments, Android Studio provides developers with two methods for passing parameters: Safe Args and Bundle.
3.1 Transferring Data using Bundles
When passing data using the Bundle, the Bundle object is first created and then navigate() is used to pass it to the destination, as shown below.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tv.setOnClickListener {
Bundle bundle = new Bundle(a); bundle.putString("key"."from fragmentA");
Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB,bundle); }}Copy the code
The recipient then uses the getArguments() method to get the data passed by the Bundle, as shown below.
String keyStr = getArguments().getString("key");
Copy the code
3.2 Transferring data using Safe Args
First, add the CLASspath configuration in your project’s build.gradle, as shown below.
dependencies {
def nav_version = "2.3.2"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
Copy the code
Then, add the Apply Plugin script to your app’s build.gradle, as shown below.
apply plugin: 'androidx.navigation.safeargs'
Copy the code
After the configuration is complete, the rebuild project is generated{module}/build/generated/source/navigation-args/{debug}/{packaged}/{Fragment}Dircetions
, as shown below.
If you need to pass data to the destination page, first follow these steps to add parameters to the destination page that receives it. Navigation provides a subtag argument that can be used to pass arguments.
First, in the Navigation Editor, click on the destination page to receive the parameters, and in the Attributes panel, click Add (+). Then, in the Add Argument Link window that displays, enter the parameter name, parameter type, whether the parameter can be null, and default value (if required) by clicking the Add button, as shown below.
Click the Text TAB to switch to the XML view, and you’ll see the generated code below.
<argument
android:name="key"
app:argType="string"
app:nullable="false"
android:defaultValue="Navigation parameter transfer" />
Copy the code
We then pass the data in fragmenta.java using the following code, as shown below.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
Button btnB = view.findViewById(R.id.btn_b);
btnB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentADirections.ActionFragmentAToFragmentB action=FragmentADirections.actionFragmentAToFragmentB().setKey("Parameter passing via safeArgs");
Navigation.findNavController(v).navigate(action); }});return view;
}
Copy the code
Accept using the following method in the onCreate method of the accepted page.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String name= FragmentBArgs.fromBundle(getArguments()).getKey();
}
}
Copy the code
4. DeepLink
When an application receives a notification and wants the user to click on the notification and go directly to the page showing the notification, this is the most common scenario for DeepLink, and the Navigation component provides support for DeepLink.
DeepLink can be used in two different scenarios: PendingIntent and real URL links, both of which can be used to jump to the page specified in the application.
4.1 PendingIntent
PendingIntent is typically used for message notifications. When an application receives a notification and wants the user to click on the notification to go directly to the specified page, it does so with PendingIntent.
For example, click the button in MainActivity to bring up the notification bar, and click the notification bar to go to the specified NotificationActivity page.
public class MainActivity extends AppCompatActivity {
NotificationManager manager=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(a); }private void init(a) {
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
// Note that once the notification channel is established, it cannot be modified
NotificationChannel channel =new NotificationChannel("normal"."Normal",NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
NotificationChannel channel2 =new NotificationChannel("important"."Important",NotificationManager.IMPORTANCE_HIGH);
manager.createNotificationChannel(channel2);
}
Button pending=findViewById(R.id.btn_pendingintent);
pending.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendNotification();
}
});
}
void sendNotification(a){
Intent intent =new Intent(this,NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this.0,intent,0);
// use NotificationCompat compatible with systems prior to 8.0
// val notification = NotificationCompat.Builder(this,"normal")
Notification notification = new NotificationCompat.Builder(this."important").setContentTitle("This is content title").setContentText("This is content text").setStyle(new NotificationCompat.BigTextStyle().bigText("Learn how to build notification,send any sync data,and use voice actions.Get the " +
"official Android IDE and developer tools to build apps for Android.")).setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background)))
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background))
.setContentIntent(pi)
.setAutoCancel(true).build(a); manager.notify(1,notification); }}Copy the code
Then, we need to create a new notification destination page. To differentiate the MainActivity, we put only a TextView component on the NotificationActivity page, as shown below.
public class NotificationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification); }}Copy the code
Then run the code above to get the final result shown below.
4.2 the URL
When browsing a page on a website using a mobile browser, users can open the corresponding application page using a web browser. If you have our app on your phone, DeepLink will open the page. If not, the web site can navigate to the download page of the application to direct the user to install the application.
First, add a
<fragment
android:id="@+id/deepLinkSettingsFragment"
android:name="com.michael.deeplinkdemo.DeepLinkSettingsFragment"
android:label="fragment_deep_link_settings"
tools:layout="@layout/fragment_deep_link_settings"> <! -- Add a <deepLink/> tag to destination --> <deepLink app: URI ="www.YourWebsite.com/{params}" />
</fragment>
Copy the code
As shown above, the APP: URI fills in the corresponding Web page address of the site, and the parameters in {params} are passed to the page via the Bundle object.
Then, set the
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".DeepLinkActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <! -- Set the <nav-graph/> tag for the Activity --> <nav-graph Android :value="@navigation/nav_graph"/>
</activity>
</application>
Copy the code
After the above Settings, it’s time to test our functionality. We can enter the corresponding Web address in the Google App, or use the ADB tool, using the command line to complete the test operation.
adb shell am start -a android.intent.action.VIEW -d "http://www.YourWebsite.com/fromWeb"
Copy the code
After executing the command, the phone opens deepLinkSettingsFragment directly. In this Fragment, we can get the corresponding argument (fromWeb) from the Bundle object to do the following operations.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_deep_link_settings, container, false);
Bundle bundle = getArguments(a);if(bundle ! = null){ String params = bundle.getString("params");
TextView tvDesc = view.findViewById(R.id.tvDesc);
if(! TextUtils.isEmpty(params)){
tvDesc.setText(params); }}return view;
}
Copy the code
The running effect is shown in the figure below.Reference:
Lifecycle Android LiveData Android Jetpack (3) ViewModel Android Jetpack (2) Lifecycle Android Jetpack architecture component (I) with AndroidX