美文网首页
Android Navigation组件(三)

Android Navigation组件(三)

作者: SimpleFunc | 来源:发表于2020-10-13 17:16 被阅读0次

    在组件化项目中使用Navigation

    Navigation组件目前并不能完美的支持组件化项目,主要问题是在module中声明的graph中destination不能直接被App引用到,在运行时会找不到对应的destination. 主要navigation资源的原因,目前设计中Navigation graph是独立的,graph中声明的destination是无法共享的。

    虽然Navigation graph中可以include其他的navigation graph, 但是include之后的graph还是无法共享声明的destination。

    官方近期更新了Navigation组件,支持了Dynamic module,新增了一个<include-dynamic/>实现,不支持deepLink. 由于国内使用不了该功能,就不再描述了。

    其他实现方式

    1. 只有一个navigation graph

    将所有模块中的fragment都声明在App的一个Navigation graph内,这样是可行的,但是这种方式解耦违反组件化的逻辑,而且只有一个navigation graph,所有destination的改动都需要修改这个graph,维护成本高。

    1. 通过include graph实现跳转

    App中的Nav graph include其他模块的Nav graph,然后通过action跳转到下个Nav graph, 如:

    <action
          android:id="@+id/action_to_next_fragment"
          app:destination="@navigation/nav_graph2" />
    

    调用这个action之后是可以跳转到下个Nav graph中声明的app:startDestination对应的fragment. 如果下个nav_graph没有声明startDestination是不行的。

    这个方案也有一个很大的缺陷,就是不能直接Navigation到include的graph中的非startDestination fragment. 只能在graph内部进行跳转。而且声明的全局action都跳转不过去。

    1. deepLink
      使用deepLink可以解决这个问题,跟方案2前面的步骤一样。然后需要在模块中对外暴露的fragment加
      <deepLink />, 这样就可以直接navigate过去。 这个方案目前是最可行的方案,但是感觉deepLink被滥用,因为deepLink的真正作用是通过外部跳转进入。对于比较复杂的项目,可能好多fragment都需要添加deepLink。而且deepLink的传参数格式需要完全匹配,容易出错。

    2. 自动合并Nav graph
      可以像官方处理AndroidManifest.xml一样,在编译时将所有module中的nav_graph文件中声明的destination都合并到app中的nav_graph文件中,理论上可以解决该问题。但是这个方案有也有很多要考虑的问题

    存在的问题:

    • AndroidManifest自动生成的文件,不是用户创建的,而且在其他用户生成的layout文件中有依赖,如果在编译前直接修改的话就不太优雅。合并只能合并到app的nav graph,每次编译都需要检查是否合并,合并之后的文件处理不太优雅。

    若是直接合并到app的nav graph中,则需要一个备份文件,在编译完成之后是需要还原回去的,这个操作本身就不太合理。正常的操作将所有nav graph文件生成为一个新的xml文件,生成到build/generated/文件下,然后修改布局中app:navGraph中的对应的依赖,由于这些布局文件不是生成的,都是开发者自己创建的,所以不太优雅。而且需要寻找声明app:navGraph的地方,编译前修改,编译完成之后需要还原。

    还有一种方案就是修改编译之后的resouce.arsc文件,这个操作比较复杂,需要解ResourceTable,找到对应的资源文件,修改生成新的饿resouce.arsc替换就行了。这个方案比较复杂,而且兼容性问题比较多,需要考虑Android系统和gradle,Android编译API的兼容性问题,开发和维护成本都比较高。

    这个方案应该是最合理的方案,官方后面可能会解决这个问题。

    Navigation组件与Router

    在组件化项目中一般都会使用Router来导航,由于之前的Router方案都是针对Activity的,之前的fragment添加,替换,移除等操作严重依赖Activity, 所以使用Router直接跳转到对应的fragment是比较麻烦的。使用navigation组件之后就可以比较简单的实现了。

    以前Router绑定的是URI和activity的class, 一般都是通过注解自动绑定。现在需要定URI, fragment或action或deepLink. 如果deepLink格式统一都不需要绑定,直接使用即可。注解需要做调整。
    例如:绑定URI和Fragment, 之前的绑定的注解是这样的:

    @Route(path = "/test/list")
    class TestActivity : Activity {
          ...
    }
    

    因为navigation跳转到Fragment并不需要Fragment的class,需要的是在nav graph声明的id. 所以需要注解添加参数来绑定,可以改为:

    @Route(path = "/test/list", resId = R.id.testfragment)
    class TestFragment : Fragment {
          ...
    }
    

    或者是deepLink, 如果path与deepLink的URI一直都不用绑定

    @Route(path = "/test/list", deepLink = "app://test/list")
    class TestFragment : Fragment {
          ...
    }
    

    action不太一样,action针对的是动作,所以不应该将包含action的注解声明在Fragment上.可以声明在方法上,如:

    object NaviControllerHelper{
    
        @RouteAction(path = "/test/list")
        fun navigateToDetail(navController: NavController){
            navController.navigate(R.id.action_to_detail)
        }
    
    }
    

    然后通过注解获取到方法名称,反射调用这个方法即可。

    相关文章

      网友评论

          本文标题:Android Navigation组件(三)

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