Android 组件化探索与实践

栏目: IOS · Android · 发布时间: 6年前

  • 在 AndroidStudio 开发 Android 项目时,使用 Gradle 来构建,Google 官方提供了对应的 Gradle 插件,方便构建过程
  • Android 工程往往会根据业务或功能划分为多个 Module(模块) ,一个主 Module,依赖 android application 插件来,该插件提供构建和打包 Android 应用等任务。主 Module 中通常标识了 Application 的入口及首个被启动的 Activity 等。
apply plugin: 'com.android.application'
复制代码
  • 其他 Module 大多依赖 android library 插件,在应用打包时,依赖了 android library 插件的 Module 会被一同打到 apk 中。
apply plugin: 'com.android.library'
复制代码
Android 组件化探索与实践
  • 之所以划分多个 Module,主要是利用 Android 开发中的 module 这个概念,将一个"功能"或"业务"作为一个 module,每个功能的代码都在自己所属的 module 中添加,module 之间在没有显示的声明依赖关系时是不能相互访问的,这样能够相对的降低耦合,易于管理。

  • 但这样的设计在各个功能相互比较独立的情况下是比较合理的,但在业务比较复杂,功能耦合严重的项目中将难以维护。其主要的缺点有:

    • Module 粒度不好掌控,划分不合理,组织很混乱

    • Module 间相互依赖,关系复杂,耦合严重,且不方便重构和迁移

    • 代码调试不够灵活,修改少量代码也需要运行整个项目查看结果,浪费时间;

组件化设计

粒度划分与组织

  • 业务 Module 划分太细,难以组织,依赖复杂;业务和基础库、公共库之间没有明显区分,组织混乱;

  • 分层

    • 基础层
      • baselib: 基础库
        • 职责:底层网络封装(network)、通用 工具 类、json解析、加密算法
        • 依赖:Gson、Glide、okHttp、Retrofit
      • framework
        • 职责: MVP、Router
        • 依赖:无
    • 公共层 - common
      • 职责: 业务相关工具类,业务相关常量、TitleBar、公共资源等
      • 依赖:api ':baselib' ':framework'
    • 业务层 - modules
      • 职责: 根据业务场景划分的多个模块,包括主 module 和多个业务 module,为了便于称呼,把一个业务 module 称为一个"组件"
      • 依赖: implementation ':common'
  • 如此一来,整个工程的结构被分为三层,日常开发基本只需要关注最后一层即可。工程架构变成了一个主模块挂载多个业务模块,共同依赖几个功能模块的模式,将这种结构称之为**"组件化"**结构。层次结构及依赖关系图:

    Android 组件化探索与实践
  • 理想情况下,主模块承载的业务能力应该尽可能的少,可以只作为整个应用的"壳儿",除应用的初始化配置及主 activity 外,尽量不包含其他业务。

  • 主模块决定挂载哪些业务组件,在应用的初始化过程中进行配置。

组件间解耦

  • 组件间通信:接口

    • 业务组件间依赖通过接口发生,实现类不发生直接依赖关系

    • 把每个业务组件对外提供的接口统一存放,可以抽成一个单独模块,比如 service,其中 common 依赖 service

    • 在应用启动时将所有组件的接口注册到接口管理器中,以便于在任何一个业务组件中,都可以访问到其他组件的接口,进而与之通信。当然,接口的实现类在对应的业务组件内。

      Android 组件化探索与实践
  • 组件间跳转:Router

    • 使用现有 Router 机制,放在 framework 中
    • Router 实现了从 String -> Class 的映射,也就实现了解耦

快速运行调试

  • 目标:日常开发中,业务组件可以单独运行。这样,在针对某个组件修改需求时,可以只运行该组件就可以看到结果或者单步调试,提高编译速度,节省时间。应用打包时,业务组件依然一并输出到 app 中。
  • 基本思想:既然业务组件即可以单独调试,又可以被主 Module 依赖,那么业务组件依赖的 Android 插件就需要动态配置。可以在 debug 模式下,每个组件不再依赖 'com.android.library',而是依赖 'com.android.application' 插件,release 模式下,组件依然依赖 'com.android.library' 插件。这样能够实现,在 debug 模式下,组件以 application 的形式存在,在 release 模式下,组件依然以 library 的方式打到同一个 apk 中。
  • 实现方式:自定义 gradle 插件,根据项目的配置文件(如 当前是否为debug模式、哪个 module 是主module,哪些是组件),动态选择依赖模式 'com.android.library' 或 'com.android.application'
  • 还要解决的问题
    • 应用初始化配置

      • 很多工具类都需要初始化才能使用,最常见的是传入 context,我们一般在 app 的 Application 的 onCreate 时对这些类进行初始化工作。
      • 同理,当组件以 application 方式运行时,我们也可以指定入口 Application,来进行一些初始化工作,注意,该 Application 只有在 debug 模式下才起作用
      • 可以通过 gradle 的 sourceSets 的配置,指定 debug 模式下 java 目录和 res 目录
    • 指定 launcher activity

      • 同样,通过 gradle 的 sourceSets 的配置,也可以指定 manifest 文件,就可以在 manifest 中配置 launcher activity

        sourceSets {
                main {
                    if (Boolean.valueOf(rootProject.getProperties().get("isDebug"))) {
                        manifest.srcFile 'src/main/debug/AndroidManifest.xml'
                        java.srcDirs = ['src/main/java', 'src/main/debug/java']
                        res.srcDirs = ['src/main/res', 'src/main/debug/res']
                    }
                }
            }
        复制代码

其他需要解决的问题

  • 组件与接口的注册
    • 挂载哪些业务组件应该由主模块决定,这样甚至可以实现动态下发配置,来挂载不同的业务组件
    • 接口的注册应该由每个组件自己决定,组件初始化时,决定要对外提供哪些接口
    • 业务组件和接口的注册应该尽可能早,以便于其他组件的访问。无疑在应用启动初期就要进行注册以及必要的初始化工作,可以选择在主业务的 application 的 onCreate 生命周期注册组件。而且主模块不能与其他业务组价产生依赖,一种比较好的方式是通过反射解耦。
    • 另外,业务组件以 library 运行时,是没有 application 的,需要给它制造一个类似的初始化时机。可以定义类似具有 onCreate 方法的接口,在主模块中依赖该接口,并通过反射,对业务组件进行初始化工作。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Domain-Driven Design

Domain-Driven Design

Eric Evans / Addison-Wesley Professional / 2003-8-30 / USD 74.99

"Eric Evans has written a fantastic book on how you can make the design of your software match your mental model of the problem domain you are addressing. "His book is very compatible with XP. It is n......一起来看看 《Domain-Driven Design》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试