构建单Activity的APP——组件化「下」

931 阅读2分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

终于到了《构建单Activity的APP》系列的最后一篇,大家一路看来,或许会觉得我一直都在介绍相关知识点,也没配合代码一步步带着大家去构建项目,这是因为我不想在很多太细的地方浪费时间,文末会贴出代码仓库地址,帮助大家理解文中讲解的知识点。下面开始介绍构建单Activity的实操环节。

构建模块

我们这次的实验将用到俩个模块:登录模块和测试模块。构建test模块的作用是用来演示与登录模块作通信的。

按照前文步骤建立一个「module_login」模块,这个模块里放置一个简单的LoginFragment,效果图如下(代码在文末链接中):

image.png

我们还需要构建一个test模块:

image.png

为每个业务模块提供NavGraph

构建了模块之后,我们需要为每个模块建立个NavGraph。 test模块的nav_test.xml

<navigation
    android:id="@+id/nav_test"
    app:startDestination="@id/test1Fragment">

    <fragment
        android:id="@+id/test1Fragment"
        android:name="com.example.module_test.Test1Fragment"
        android:label="Test1Fragment" />
    <fragment
        android:id="@+id/test2Fragment"
        android:name="com.example.module_test.Test2Fragment"
        android:label="Test2Fragment" />
</navigation>

login模块的nav_login.xml

<navigation
    android:id="@+id/nav_login"
    app:startDestination="@id/testLoginFragment">
    <fragment
        android:id="@+id/testLoginFragment"
        android:name="com.example.module_login.TestLoginFragment"
        android:label="TestLoginFragment" >
        <deepLink
            android:id="@+id/deepLink"
            app:uri="android-app://example/login" />
    </fragment>
</navigation>

注意登录模块的NavGraph中,增加了一个<deepLink>。通过这个标识我们就可以使用Navigation提供的深链接功能实现跨模块的导航,不过前提这些fragment是在一个NavGraph中的。

app模块整合NavGraph

所以为了实现一个NavGraph的先决条件,我们还需要在主模块app中,将模块的所有导航图都整合到一张图中。我们的组件化一般设计的是菱形的结构,或者说是一种主模块依赖所有模块的结构。所以主模块是可以获取到所有的模块中的实例的,当然包括子模块中的NavGraph。

在主模块中我们可以将所有子模块的NavGraph以嵌套图的形式加载到一个NavGraph中。

nav_main.xml

<navigation
    android:id="@+id/nav_main"
    app:startDestination="@id/nav_test">
    <include app:graph="@navigation/nav_login" />
    <include app:graph="@navigation/nav_test" />
</navigation>

注:app的NavGraph不可以将模块中的Fragment设为起始页,会找不到这个fragment而闪退。

这时再使用Navigation提供的深链接导航函数就可以导航了。

val request = NavDeepLinkRequest.Builder
            .fromUri("android-app://example/login".toUri())
            .build()
    navC.navigate(request)

因为是这个方案Navigation支持的,所以按下设备的物理返回键,也能从loginFragment返回到test2Fragment。

注:此方法为隐式深层链接,不会像显式深层链接在导航时替换返回堆栈。

导航的组件化方案就此介绍完了。至于跨模块的fragment之间的通信,建议在菱形结构的最底层,构建一个类似于Common的模块,或者就在Common模块中根据业务构建适量的Activity级别的ViewModel用来跨模块通信。

注意事项:

  • 模块中的布局文件名不能重复。
  • 布局文件中应该用fragment当作navhost,用containerFragment有问题。拿不到navHost.

参考文档:

项目代码地址