Navigator

作者: fyg | 来源:发表于2021-08-10 02:06 被阅读0次

    developer.android.google.cn/jetpack

    navigation

    在目的地之间传递数据

    对navigation中action参数的destination,popUpTo,popUpToInclusive的一点笔记

     destination顾名思义是导航的目的地,popUpTo(tag) 跳转到tag,并弹出tag之上的fragment,popUpToInclusive=true会弹出tag,false则不会弹出。
    
    

    【Android进阶必学】JetPack指路明灯—Navigation

    Jetpack Navigation工作原理

    Fragment不用再每次切换是都重新创建了
    jetpack系列之自定义FragmentNavigator


    Android Navigation 如何动态的更换StartDestination &&保存Fragment状态


    Google控件Navigation进阶使用

    2.统一配置Animation
    fun getObjectNacAction(id: Int, singleTop: Boolean = true, popid: Int? = null, clearPop: Boolean = false) =
           NavActionBuilder().apply {
               destinationId = id
               navOptions {
                   if (popid != null) {
                       popUpTo(popid) {
                           inclusive = clearPop
                       }
                   }
                   launchSingleTop = singleTop
                   anim {
                       popEnter = R.anim.slide_left_in
                       popExit = R.anim.slide_left_out
                       enter = R.anim.push_left_in
                       exit = R.anim.push_right_out
                   }
               }
           }
    
    


    开始使用 Navigation

    
    
     要避免这种重复的话,可以在从C 到A 的action中指定 app:popUpTo 还有 app:popUpToInclusive 属性,如下:
    
    <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>
    
    
    在到达了目的地 C 之后,回退栈中包含了目的地 A,B,C 的实
    例.当导航回目的地 A 的时候,我们同时 popUpTo A ,这意味着
    我们在导航的时候从回退栈中删除了 B,C. 伴随着 
    app:popUpToInclusive="true" 我们同时弹出了回退栈中的第
    一个 A.要注意如果你没有使用 app:popUpToInclusive="true" 
    这个属性的话,你的回退栈中将会包含两个A 的实例.
    
    
    

    谷歌官方组件Navigation你会用了吗?

    两种跳转分别是传入nav_graph.xml当中的action id和resource id。
    两种方法都可以实现跳转,但是我更建议用第一种,因为第一种可以配合着过渡的动画使用。
    
    可以看到当我们倒C之后,后台堆栈当中包括A、B、C单个实例。当我们通过popUpTo A回到A的时候,意味着我们从堆栈当中把B和C删除了。当我们使用app:popUpToInclusive =“true”的时候,我们还会把A弹出堆栈并有效的清除它。如果我们没有使用app:popUpToInclusive =“true”那么也意味着我们的堆栈当中包含两个A的实例。
    
    
    <action
            android:id="@+id/action_c_to_a"
            app:destination="@id/a"
            app:popUpTo="@+id/a"
            app:popUpToInclusive="true"/>
    
    
    
    Navigation.findNavController(it).navigate(R.id.twoFragment)
    
    对于Button控件来说,还有另一种实现跳转的方法
    
    view?.let { Navigation.findNavController(it).navigate(R.id.twoFragment)
    
    

    问题即使以前的片段名为popUpTo的根,Android导航框架仍会显示后退箭头

    
    使用Android导航框架时,我将IntroFragment作为根,将MainFragment作为IntroFragment的目标 . 在IntroFragment中我打电话:
    
    view.findNavController().navigate(IntroFragmentDirections.actionIntroFragmentToMainFragment())
    该操作的xml是:
    
    <action android:id="@+id/action_introFragment_to_mainFragment" app:destination="@id/mainFragment"
                app:exitAnim="@anim/slide_out_right" app:popUpTo="@+id/main" app:popUpToInclusive="true"/>
    尽管有popUpToInclusive,但MainFragment工具栏中仍然会出现一个后退箭头 . 我一直无法找到摆脱它的方法 . 我已经确认按后面的软键确实会退出活动 .
    
    
    




    Navigation问题详解——Fragment创建新的实例

    ···

    这样就会出现一个问题,可能我们之前的OneFragment保存一些状态或者数据,当我们跳转OneFragment的时候,因为创建新的实例导致我们之前保存状态或者数据全部消失。

    3.resource id替换为action id
    看过我之前代码的同学,可能会注意到我特意强调
    findNavController().navigate(R.id.action_oneFragment_to_twoFragment)

    这里的id最好用action id,这一种可以配合着action里的动画使用,当然也可以配合着action里的属性popUpTo popUpToInclusive来使用。
    之前有位同学在公共号给我留言,问下了Demo之后,为什么设置 popUpTo/popUpToInclusive不起作用,问题就在这里应该是action Id

    问题依旧....
    看似,我们在回退的时候,正常了。但是,我们的问题依旧存在,每次点击的时候依然会创建一个新的Fragment,一个新的实例,只是我们在创建新的实例的时候,把之前的给清除了而已。
    我会在下一篇文章介绍如何解决这个问题!

    ···


    Jetpack源码解析---Navigation为什么切换Fragment会重绘?

    看到这里就很清楚了吧,Fragment的切换是通过replace方式
    来切换的,并且加入回退栈,也就是说每次切换Fragment,都
    会销毁视图和重新创建视图。至于为什么用这种方式我是真
    的想不到,也没搞清楚初衷是什么?按照我们目前的开发来
    说,Fragment的切换通常都会使用hide()、show(),而
    replcae()的方式很少用,替换会把容器中的所有内容全都替
    换掉,有一些app会使用这样的做法,保持只有一个fragment
    在显示,减少了界面的层级关系。
    
    
    不仅仅是这样,上篇文章有小伙伴问切换了Fragment之后,
    点击返回按钮,发现之前的Fragment重走了onCreateView流
    程,这就意味着之前的状态没了。对于这个问题其实根据上
    面的分析,也能大概想到是因为什么,但是返回按钮的操作
    我之前还真没有看过源码,所以这次顺便了解一下:
    
    
    
    到这里就基本结束了,我只分析了一个大概,可以了解到点击返回按钮,同样也会重新创建视图,也就是onCreateView会重新走一遍。
    
    
    
    

    .1 建议

    这里我的建议是:如果你的每个Fragment真的每次都需要重新绘制的话,你可以考虑使用Navigation组件来实现,毕竟通过Navgation组件真的很方便帮助我们切换导航,而且虽然布局会重新绘制,但是Google的官方Demo–SunFlower还是使用了这种方式,所以这里面我觉得:官方推荐我们使用Jetpack组件中的ViewModelLiveData…等,可以发现SunFlowerdemo中,即便是切换Fragmengt也不会有很明显的卡顿现象,因为每个Fragment即便重新绘制,但是View所对应的ViewModel还在,数据并不需要重新加载或者请求,当然这仅仅是我自己的看法啊.

    但是如果你没有这种场景的话,建议还是用普通的方式我们自己来控制切换吧,这样无论是基于Drawerlayout还是BottomNaivgationView的话,我们可以自己实现切换。这块我也不是很确定哈,也希望听取大家的意见和建议。

    因为每个Fragment即便重新绘制,但是View所对应的ViewModel还在,数据并不需要重新加载或者请求,


    Android-Jetpack笔记-Navigation之Fragment支持复用


    Jetpack路由组件学习:深入理解功能强大的Navigation架构之接管系统的返回操作




    Android Navigation的四大要点你都知道吗?

    
    
    

    deepLink


    popUpTo属性表示堆栈返回到某个界面,其后的栈数据清空
    //popUpToInclusive属性为true表示回到指定界面时,界面栈中是否还包括当前界面
    //(如果栈中已经包含了指定要跳转的界面,那么只会保留一个,不指定则栈中会出现两个
    //界面相同的Fragment数据)
    
    
    a->b->c ,从c到a时,指定app:popUpTo="@id/listFragment" 
    ,app:popUpToInclusive="true"  发现是新开了一个a,之前的a 
    走了,onDestroyView 和  onDestroy 方法,
    
    
    如何 做到 从c到a时复用 a,也就是不销毁之前的那个,也不开启新的,直接复用老的fragment. 答案是使用popBackStack 方法,见下下图:情况2

    情况1

    a(ListFragment),b(DetailFragment),c(EditorFragment) 三个fragment分别在 onCreate,onCreateView,onViewCreated,onDestroyView,onDestroy方法中加入日志,其中 b 启动c的 action中加入了 app:popUpTo="@id/listFragment" ,app:popUpToInclusive="true"

    使用修复过的NavHostFragment

    image.png

    使用系统自带的NavHostFragment

    image.png

    【Android进阶必学】JetPack指路明灯—Navigation

    navigateUp

    navigateUp与物理返回键的功能类似,即返回当前页面堆栈的栈顶页面,代码如下所示。

    Navigation.findNavController(it).navigateUp()
    当我们从A路由到B,B路由到C后,通过上面的代码,使用navigateUp返回,则路由返回路径为C到B,B到A,如果在A继续调用navigateUp,则不会响应,因为当前栈中只有唯一一个页面,而且是startDestination,所以不会再响应返回操作。

    情况2

    popBackStack

    navigateUp只能响应向上一级的路由控制,而不能跨级进行路由返回,popBackStack则是对其的补充,可以指定路由返回的action,代码如下所示。
    Navigation.findNavController(it).popBackStack(R.id.loginFragment, true)

    当我们从A路由到B,B路由到C后,通过popBackStack返回,指定要返回到的Fragment的id,即可直接返回到指定位置,第二个参数inclusive,代表返回操作是否包含指定的Fragment id。

    这里要注意的是,当你指定返回到A,同时inclusive为true的
    时候,A也是不会被移除的,因为A是栈顶。  
    
    但如下图所示,界面并没有执行 a 的onDestroy 方法和
    oncreate 方法 ,说明 a 并没有销毁
    
    

    使用系统自带的NavHostFragment

    inclusive为true时


    image.png

    inclusive为false时


    image.png

    使用修改过的NavHostFragment

    inclusive为true时

    image.png

    inclusive为false时

    image.png

    从验证结果看不管inclusive为false还是true, a 页面始终没有 被销毁。

    使用修改过的NavHostFragment和系统自带的NavHostFragment我区别?

    修改过的NavHostFragment 用action开页面时不会调用onDestroyView和onDestroy方法,而系统自带的会调用。
    
    再考虑下面这样一个场景,A—B,B路由到C的时候,设置popUpTo="@id/A",如果popUpToInclusive=false,则跳转到C之后的路由栈为A—C,如果设置为true,则只剩下A在路由栈中,代码如下所示。
    

    如上文字经过验证发现是错的,正确的结论是:

    使用修改过的NavHostFragment,popUpToInclusive=true的情况
    image.png
    使用修改过的NavHostFragment, popUpToInclusive=false的情况
    image.png

    场景,A—B,B路由到C的时候,设置popUpTo="@id/A",如果popUpToInclusive=false,则跳转到C之后的路由栈为A—C,如果设置为true,则只剩下c在路由栈中,





















    相关文章

      网友评论

          本文标题:Navigator

          本文链接:https://www.haomeiwen.com/subject/cedtbltx.html