activity 点击后传递数据给fragment_Android-Jetpack笔记-Navigation之Fragment使用

Navigation是一种导航的概念,即把Activityfragment当成一个个的目的地Destination,各目的地形成一张导航图NavGraph,由导航控制器NavController来统一调度跳转,本文会先简单分析下AS自带的示例代码。

Jetpack笔记代码

本文源码基于SDK 29,IDE是Android studio 3.5.3

使用

创建工程,引入依赖,

 implementation 'androidx.navigation:navigation-fragment:2.2.2'
 implementation 'androidx.navigation:navigation-ui:2.2.2'

然后new activity,选中bottom navigation activity,IDE会创建出3个fragment和viewModel,1个activity和布局文件,1个菜单文件bottom_nav_menu,1个导航图文件mobile_navigation,运行如下:

48dadee26e1d65c335639c89020e2c83.png

先看下布局文件,

 <androidx.constraintlayout.widget.ConstraintLayout>
     <!-- 底部的导航view,菜单文件里定义了3个item -->
     <com.google.android.material.bottomnavigation.BottomNavigationView
         android:id="@+id/nav_view"
         app:menu="@menu/bottom_nav_menu" />
 ​
     <!-- fragment作为页面容器,navGraph指定了导航图的结构 -->
     <fragment
         android:id="@+id/nav_host_fragment"
         android:name="androidx.navigation.fragment.NavHostFragment"
         app:defaultNavHost="true"
         app:navGraph="@navigation/mobile_navigation" />
 ​
 </androidx.constraintlayout.widget.ConstraintLayout>

来到导航图文件mobile_navigation

 <navigation xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/mobile_navigation"
     app:startDestination="@+id/navigation_home">
 ​
     <fragment
         android:id="@+id/navigation_home"
         android:name="com.holiday.jetpackstudy.navigation.ui.home.HomeFragment"
         tools:layout="@layout/fragment_home" />
 ​
     <fragment
         android:id="@+id/navigation_dashboard"
         android:name="com.holiday.jetpackstudy.navigation.ui.dashboard.DashboardFragment"
         tools:layout="@layout/fragment_dashboard" />
 ​
     <fragment
         android:id="@+id/navigation_notifications"
         android:name="com.holiday.jetpackstudy.navigation.ui.notifications.NotificationsFragment"
         tools:layout="@layout/fragment_notifications" />
 </navigation>

这里列出了所有目的地,其中startDestination指定了导航图的起点即首页HomeFragment,把AS切换成design视图,

c5c1070ab16d81373bcec723e7fd47bc.png

这样可以用可视化的方式管理导航图结构,然后来看activity,

 public class NavigationActivity extends AppCompatActivity {
 ​
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         setContentView(R.layout.activity_navigation);
         BottomNavigationView navView = findViewById(R.id.nav_view);
         //用3个目的地fragment构建配置类
         AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                 R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
                 .build();
         //用fragment容器构建导航控制器
         NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
         //为导航控制器设置配置类
         NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
         //关联NavigationView和导航控制器
         NavigationUI.setupWithNavController(navView, navController);
     }
 ​
 }

代码大致就这些,接下来看看内部实现。

原理

AppBarConfiguration.Builder将目的地(以下目的地均指页面)存储起来,

 //AppBarConfiguration.java
  Builder(int... topLevelDestinationIds) {
      for (int destinationId : topLevelDestinationIds) {
          mTopLevelDestinations.add(destinationId);
      }
  }

NavigationUI.setupActionBarWithNavController也是简单的设置参数,

 //NavigationUI.java
 void setupActionBarWithNavController(AppCompatActivity activity,NavController navController,
                                      AppBarConfiguration configuration) {
     navController.addOnDestinationChangedListener(
         new ActionBarOnDestinationChangedListener(activity, configuration));
 }

然后NavigationUI.setupWithNavController关联了NavigationView和导航控制器,

 //NavigationUI.java
 void setupWithNavController(final BottomNavigationView bottomNavigationView,
             final NavController navController) {
     //设置底部导航的点击事件
     bottomNavigationView.setOnNavigationItemSelectedListener(
         new BottomNavigationView.OnNavigationItemSelectedListener() {
             @Override
             public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                 //底部导航切换按钮时
                 return onNavDestinationSelected(item, navController);
             }
         });
     //在目的地发生切换的时候,更新底部导航的选中状态,先不看
     navController.addOnDestinationChangedListener(xxx)
 }
 ​
 boolean onNavDestinationSelected(MenuItem item,NavController navController) {
     //导航
     navController.navigate(item.getItemId(), null, options);
 }

来到NavController

 //NavController.java
 //省略调用链来到
 void navigate(NavDestination node, Bundle args,
               NavOptions navOptions, Navigator.Extras navigatorExtras) {
     NavDestination newDest = navigator.navigate(node, finalArgs,
                 navOptions, navigatorExtras);
 }

点进navigator.navigate,会发现有多个实现类,

da8a5f477a1dd3dada50dc152a4bf5b3.png

这里我们使用的是FragmentNavigator

 //FragmentNavigator.java
 NavDestination navigate(Destination destination, Bundle args,
             NavOptions navOptions, Navigator.Extras navigatorExtras) {
     //获取fragment类名
     String className = destination.getClassName();
     //反射创建fragment
     Fragment frag = instantiateFragment(mContext, mFragmentManager,
                 className, args);
     //熟悉的fragment事务
     FragmentTransaction ft = mFragmentManager.beginTransaction();
     //用replace的方式展示fragment
     ft.replace(mContainerId, frag);
     //提交事务
     ft.commit();
 }

这里可以看出一个问题,每次切换目的地,fragment是反复销毁重建的,按照谷歌推荐的1个APP只需1个activity的思路开发,这样是没问题的,但是这里的fragment是作为首页的3个常驻页面,我们是希望能够保存起来的,毕竟,销毁重建需要重新请求网络数据,重新初始化view,严重影响用户体验,笔者将在下篇文章探讨fragment的复用方案。

参考文章

  • 掘金-Android官方架构组件Navigation:大巧不工的Fragment管理框架

13122bc78c17b8a12ba8b7de5ff71de9.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值