【JetPack】Navigation知识点总结

1、Navigation Graph:

一种新的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/my_nav_graph"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.navigation.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_homeFragment_to_detailFragment"
            app:destination="@id/detailFragment" />
    </fragment>
    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.navigation.DetailFragment"
        android:label="fragment_detail"
        tools:layout="@layout/fragment_detail" >
        <action
            android:id="@+id/action_detailFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
</navigation>

2、NavHostFragment:

一个特殊的Fragment,可以将它看作是其他Fragment的容器,Navigation Graph中的Fragment正是通过NavHostFragment进行展示的。

复制代码
<?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">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="409dp"
        android:layout_height="729dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/my_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

3、NavController:

用于在代码中完成Navigation Graph中具体的页面切换工作。

复制代码
MainActivity.java
public class MainActivity extends AppCompatActivity {
    NavController navController;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		// 这样写会报错
    	// NavController navController = Navigation.findNavController(this, R.id.fragmentContainerView);
        // 需要先通过id获取到对应的NavHostFragment容器
        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView);
        if (navHostFragment != null) {
       		 // 如果不为空,再获取到的容器对应的NavController
            navController = navHostFragment.getNavController();
        } else {
            throw new RuntimeException("NavHostFragment not found");
        }
        // 该代码的主要目的是将 ActionBar(或 Toolbar)与 NavController 关联起来,以便在使用 Android 导航组件时,ActionBar 可以自动更新其显示内容
        NavigationUI.setupActionBarWithNavController(this, navController);
    }
    
    @Override
    public boolean onSupportNavigateUp() {
        // header上返回按键好用
        return navController.navigateUp();
    }
}
HomeFragment.java
@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button);
        button.setOnClickListener(view -> {
        	// 由于最外层设置了NavController,所以这里可以通过容器中的view找到NavController
            NavController navController = Navigation.findNavController(view);
            // 通过NavController进行导航,确定目的地
            navController.navigate(R.id.action_homeFragment_to_detailFragment);
        });
    }
DetailFragment.java
@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button2);
        button.setOnClickListener((v)->{
            // 由于最外层设置了NavController,所以这里可以通过容器中的view找到NavController
            NavController navController = Navigation.findNavController(v);
            // 通过NavController进行导航,确定目的地
            navController.navigate(R.id.action_detailFragment_to_homeFragment);
        });
    }

三者之间的关系

当你想切换Fragment时,使用NavController对象,告诉它你想要去Nlavigation Graph中的哪个Fragment,NavController会将你想去的Fragment展示NavHostFragment中
实现顺序

1.创建Fragment

2.创建navgation_graph,指定fragment切换逻辑

3.在Activity的页面中添加navHostFragmrnt容器进行界面显示

4.在Activity中通过navHostFragmrnt获取到navController,并设置bar和fragment的对应关系,以及bar上返回按键生效

5.在需要触发fragment切换的位置通过获取navController进行导航,设置对应的action,确认触发后目的地
添加页面切换动画

页面之间参数传递

方法一:直接传递bundle对象(接收数据时需要知道对应key值以及value类型,并且需要判空)

复制代码
        Bundle bundle = new Bundle();
        bundle.putString("user_name", "Jay");
        NavController navController = Navigation.findNavController(view);
        navController.navigate(R.id.action_homeFragment_to_detailFragment, bundle);

接收bundle对象

复制代码
		Bundle arguments = getArguments();
		String userName = null;
		if (arguments != null) {
		    userName = arguments.getString("user_name");
		    Log.d("userName", "" + userName);
		}

方法二:引入arg插件

复制代码
		dependencies {
		    // 添加 safe-arg 插件依赖
		    classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0")
		}
		plugins {
		    id 'androidx.navigation.safeargs'
		}

        Bundle bundle = new HomeFragmentArgs.Builder()
                .setUserName("Jay")
                .setAge(20)
                .build().toBundle();
  
        HomeFragmentArgs args = HomeFragmentArgs.fromBundle(getArguments());
        String username = args.getUserName();
        int age = args.getAge();
        Log.d("Test", "userName = " + userName + "age = " + age);

NavigationUI的使用场景

Fragment切换时,设计到AppBar上的内容显示,为了方便统一管理引入NavigationUI

复制代码
public class MainActivity extends AppCompatActivity {
    private NavController navController;
    private AppBarConfiguration appBarConfiguration;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView);
        if (navHostFragment != null) {
            navController = navHostFragment.getNavController();
        }
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        // 将Appbar与Navigation建立联系
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_settings, menu);
        return true;
    }
    // 响应Meun的点击事件
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        return NavigationUI.onNavDestinationSelected(item, navController) || super.onOptionsItemSelected(item);
    }
    // 响应AppBar的返回按键
    @Override
    public boolean onSupportNavigateUp() {
        return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp();
    }
}

跳转后的假面不显示meun

复制代码
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        setHasOptionsMenu(true);
        return inflater.inflate(R.layout.fragment_setting, container, false);
    }

    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        menu.clear();
        super.onCreateOptionsMenu(menu, inflater);
    }

监听页面切换完成的回调

复制代码
        // 监听界面切换完成
        navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController navController, @NonNull NavDestination navDestination, @Nullable Bundle bundle) {
                Log.d("test","onDestinationChanged");
            }
        });

深层链接DeepLink之PendingIntent

复制代码
private void sendNotifycation() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel myChannel = new NotificationChannel(getActivity().getPackageName(), "MyChannel", NotificationManager.IMPORTANCE_DEFAULT);
            myChannel.setDescription("My NotificationChannel");
            NotificationManager notificationManager = getActivity().getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(myChannel);
        }

        NotificationCompat.Builder builder = new NotificationCompat.Builder(getActivity(), getActivity().getPackageName())
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentTitle("Deep Link")
                .setContentText("点我")
                .setPriority(NotificationManager.IMPORTANCE_DEFAULT)
                .setContentIntent(getPendingIntent());
        // 发送通知
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());

        if (ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        notificationManager.notify(notifyId++, builder.build());
    }

    private PendingIntent getPendingIntent() {
        Bundle bundle = new Bundle();
        bundle.putString("name","Jay");
        return Navigation.findNavController(getActivity(),R.id.button)
                .createDeepLink()
                .setGraph(R.navigation.my_nav_graph)
                .setDestination(R.id.detailFragment)
                .setArguments(bundle)
                .createPendingIntent();
    }

深层链接DeepLink之Url

相关推荐
Dovis(誓平步青云)2 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码3 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程4 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程8 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程8 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程8 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓9 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程9 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc1239 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium