返回顶部
首页 > 资讯 > 精选 >Android开发组件化架构设计原理实例分析
  • 362
分享到

Android开发组件化架构设计原理实例分析

2023-07-02 10:07:17 362人浏览 独家记忆
摘要

今天小编给大家分享一下Android开发组件化架构设计原理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。为什么需要组

今天小编给大家分享一下Android开发组件化架构设计原理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    为什么需要组件化

    项目是不需要组件化的。当一个项目有数十个人开发,编译项目要花费10分钟,修改一个bug就可能会影响到其他业务,小小的改动就需要进行回归测试,如果是这种项目,那么我们需要进行组件化了

    组件化和模块化

    在技术架构演进的过程一定是先出现模块化后出现组件化,因为组件化就是解决了模块化的问题。

    模块化架构

    创建一个 Project 后可以创建多个 Module,这个 Module 就是所谓的模块。一个简单的例子,可能在写代码的时候我们会把首页、消息、我的模块拆开,每个 tab 所包含的内容就是一个模块,这样可以减少 module 的代码量,但是每个模块之间的肯定是有页面的跳转,数据传递等,比如 A 模块需要 B 模块的数据,于是我们会在 A 模块的 gradle 文件内通过 implementation project(':B')依赖 B 模块,但是 B 模块又需要跳转到 A 模块的某个页面,于是 B 模块又依赖了 A 模块。这样的开发模式依然没有解耦,改一个bug依然会改动很多模块,并不能解决大型项目的问题。

    如下图所示,一开始我们定义的module之间并没有过多耦合:

    Android开发组件化架构设计原理实例分析

    然后,随着项目的不断迭代,相互调用的情况会增多,也会增加一些库的扩展和调用,工程的架构可能变为:

    Android开发组件化架构设计原理实例分析

    可以看出,各种业务之间的耦合非常严重,导致代码非常难以维护,更难以测试,扩展和维护性非常差,这样的架构肯定会被替代。

    随着时间的推移,出现了组件化、插件化等组织架构。

    组件化架构

    这里先提几个概念,我们日常业务需求开发的组件叫做业务组件,如果这个业务需求是可以被普遍复用的,那么叫做业务基础组件,譬如图片加载、网络请求等框架组件我们称为基础组件。搭建所有组件的app组件称为壳组件/工程。接下来看一张架构图:

    Android开发组件化架构设计原理实例分析

    实线表示直接依赖关系,虚线表示间接依赖。比如壳工程肯定是要依赖业务基础组件、业务组件、module_common公共库的。业务组件依赖业务基础组件,但并不是直接依赖,而是通过”下沉接口“来实现间接调用。业务组件之间的依赖也是间接依赖。最后common组件依赖所有需要的基础组件,common也属于基础组件,它只是统一了基础组件的版本,同时也提供了给应用提供一些抽象基类,比如BaseActivity、BaseFragment,基础组件初始化等。

    组件化带来的优势

    • 加快编译速度:每个业务组件都可以单独运行调试,速度提升好几倍。举个例子:video组件单独编译运行时间为3s,因为此时AS只会运行video组件以及video组件依赖的组件的task,而如果集成编译时间为10s,app所引用的所有的组件的task都会执行。可见,效率提升了3倍。

    • 提高协作效率:每个组件都有专人维护,不用关心其他组件是怎么实现的,只需要暴露对方需要的数据。测试也不需要整个回归,只需要重点测试修改的组件即可。

    • 功能重用:一次编码处处复用,再也不需要了。尤其是基础组件和业务基础组件,基本上调用者根据文档就可以一键集成和使用。

    • 确保了整体技术方案的统一性,为未来插件化公用一套底层模型做准备。

    前面有提到非大型项目一般不会进行组件化,但是就像上面提到的功能重用,这个优势并不是只能用到大型项目 。我们可以在写需求或库时完全可以拥有组件化思想,把它们单独写成一个基础组件或业务基础组件。当第二个项目来的时候正好也需要这个组件,那我们就省去了拆出这个组件的时间(因为写需求的时候很可能会造成大量耦合,后续拆分要花费时间),比如登录组件,分享组件等等都是可以在一开始就写成组件的。

    组件化需解决的问题

    • 如何解决资源配置冲突问题?

    • 业务组件如何实现单独调试?

    • 业务组件间没有依赖,如何实现页面跳转?

    • 业务组件间没有依赖,如何实现数据通信?

    • 业务组件间没有依赖,如何实现消息通信

    • 壳工程Application生命周期如何下发?

    资源冲突解决

    AndroidManifest

    每个module都有一份AndroidManifest文件来记载信息,最终生成一个App的时候,只会有一份AndroidManifest来知道APP应该去如何配置,Manifest Merge Tools 会将多个AndroidManifest合成一个,但是又冲突需要解决。

    Android开发组件化架构设计原理实例分析

    在build/intermediates/manifest_merge_blame_file下会生成一份合并报告

    <?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="Http://schemas.android.com/apk/res/android"   package="com.liang.mosic"   android:versionCode="1"   android:versionName="1.0" >   <uses-sdk       android:minSdkVersion="21"->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml       android:targetSdkVersion="30" />->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml    <uses-permission android:name="android.permission.INTERNET" />-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:12:5-67-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:12:22-64    <application-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:6:5-48:19        android:name="com.liang.mosic.ModuleApplication"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:10:9-42        android:allowBackup="true"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:7:9-35        android:appComponentFactory="androidx.core.app.CoreComponentFactory"-->[androidx.core:core:1.5.0] C:\Users\Administrator.gradle\caches\transfORMs-2\files-2.1\4c9b62de2468f1520f5d232befb24ab8\core-1.5.0\AndroidManifest.xml:24:18-86        android:debuggable="true"        android:icon="@mipmap/ic_launcher"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:8:9-43        android:label="@string/app_name"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:9:9-41        android:supportsRtl="true"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:11:9-35        android:testOnly="true"        android:theme="@style/AppTheme" >-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:13:9-40        <!-- <activity android:name=".MainActivity"> -->        <!-- <intent-filter> -->        <!-- <action android:name="android.intent.action.MAIN" /> -->        <!-- <cateGory android:name="android.intent.category.LAUNCHER" /> -->        <!-- </intent-filter> -->        <!-- </activity> -->        <activity-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:21:9-28:20            android:name="com.liang.mosic.AdaviceActivity"-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:21:19-50            android:theme="@style/AppWelcome" >-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:22:13-46            <intent-filter>-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:23:13-27:29                <action android:name="android.intent.action.MAIN" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:24:17-69-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:24:25-66                <category android:name="android.intent.category.LAUNCHER" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:26:17-77-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:26:27-74            </intent-filter>        </activity>        <activity android:name="com.liang.mosic.ModuleMainActivity" >-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:29:9-40:20-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:29:19-53            <!-- <intent-filter> -->            <!-- <action android:name="android.intent.action.MAIN" /> -->            <!-- <category android:name="android.intent.category.LAUNCHER" /> -->            <!-- </intent-filter> -->            <intent-filter>-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:35:13-39:29                <action android:name="com.liang.main" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:36:17-60-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:36:25-57                <category android:name="android.intent.category.DEFAULT" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:17-76-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:27-73            </intent-filter>        </activity>        <activity android:name="com.liang.mosic.ModuleExampleActivity" >-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:41:9-47:20-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:41:19-56            <intent-filter>-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:42:13-46:29                <action android:name="com.liang.moduleFragment" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:43:17-70-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:43:25-67                <category android:name="android.intent.category.DEFAULT" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:17-76-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:27-73            </intent-filter>        </activity>        <activity android:name="com.liang.a.MainActivity" >-->[:a] C:\Users\Administrator\Desktop\mosic-master\mosic-master\a\build\intermediates\library_manifest\debug\AndroidManifest.xml:17:9-23:20-->[:a] C:\Users\Administrator\Desktop\mosic-master\mosic-master\a\build\intermediates\library_manifest\debug\AndroidManifest.xml:17:19-61            <intent-filter>-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:23:13-27:29                <action android:name="android.intent.action.MAIN" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:24:17-69-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:24:25-66                <category android:name="android.intent.category.LAUNCHER" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:26:17-77-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:26:27-74            </intent-filter>        </activity>        <activity android:name="com.liang.b.BActivity" >-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:21:9-27:20-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:21:19-58            <intent-filter>-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:22:13-26:29                <action android:name="com.liang.b.act" />-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:23:17-61-->[:b] C:\Users\Administrator\Desktop\mosic-master\mosic-master\b\build\intermediates\library_manifest\debug\AndroidManifest.xml:23:25-58                <category android:name="android.intent.category.DEFAULT" />-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:17-76-->C:\Users\Administrator\Desktop\mosic-master\mosic-master\app\src\main\AndroidManifest.xml:38:27-73            </intent-filter>        </activity>    </application></manifest>

    最终编译出的app会将其他所有module的AndroidManifest文件合并,合并规则为:

    • 如果功能module有Application,主module没有声明,则使用功能module的Application;

    • 如果主module有定义Application,其他module没有,则使用主module的;

    • 如果功能module有多个自定义Application,解决冲突后使用;

    • 如果主module有Application,功能module也有,则解决冲突后,最后编译的主module的Application会在AndroidManifest中。

    如果子module中声明icon、theme等属性,会导致合并冲突,需要申明属性:

    xmlns:tools="http://schemas.android.com/tools"tools:replace="android:icon,android:theme"

    权限申明:

    在子module中申明的权限,会集成到主module中,四大组件也是相同的规则。shareUid只有在主module中申明,才会打包到最终的AndroidManifest中。

    独立调试

    单工程方案

    所谓的单工程方案就是把所有组件都放到一个工程下,先看一下整体的目录:

    Android开发组件化架构设计原理实例分析

    ps

    module_ 开头表示基础组件,

    fun_ 前缀表示业务基础组件,

    biz_前缀表示业务组件,

    export_前缀表示业务组件暴露接口。

    单工程利弊分析:

    • 利:一个模块修改后只需要编译一下,依赖它的其他模块就能马上感知到变化。

    • 弊:没能做到完全的职责拆分,每个模块的开发者都有修改其他模块的权限。

    首先在 gradle.properties 文件内声明一个变量:

    // gradle.propertiesisModule = true

    isModule 为 true 时表示组件可以作为 apk 运行起来,false 表示组件只能作为 library。我们根据需要改变这个值后同步下gradle即可。

    然后在某个 module 的 build.gradle 文件内用这个变量做三个地方的判断:

    // build.gradle// 区分是应用还是库if(isModule.toBoolean()) {apply plugin: 'com.android.application'}else {apply plugin: 'com.android.library'}android {defaultConfig {// 如果是应用需要指定applicationif(isModule.toBoolean()) {applicationId "com.xxx.xxx"}}sourceSets {main {// 应用和库的AndroidManifest文件区分if(isModule.toBoolean()) {manifest.srcFile 'src/main/debug/AndroidManifest.xml'}else {manifest.srcFile 'src/main/AndroidManifest.xml'}}}}

    由于library是不需要 Application 和启动Activity页,所以我们要区分这个文件,应用manifest指定的路径没有特定,随意找个路径创建即可。在应用AndroidManifest.xml里我们要设置启动页:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.sun.biz_home">    <application        android:allowBackup="true"        android:label="@string/home_app_name"        android:supportsRtl="true"        android:theme="@style/home_AppTheme">        <activity android:name=".debug.HomeActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

    library 的 AndroidManifest.xml 不需要这些:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.sun.biz_home"></manifest>

    gradle 依赖 module 的方式主要有两种:

    • implementation: A implementation B,B implementation C, 但 A 不能访问到 C 的东西。

    • api:A api B,B api C,A能访问到C的东西。

    一般来说我们只需要使用 implementation 即可,api 是会造成项目编译时间变长,而且会引入该模块不需要的功能,代码之间耦合变得严重了。不过 module_common 是统一了基础组件版本的公共库,所有组件都应需要依赖它并拥有基础组件的能力,所以基本每个业务组件和业务基础组件都应该依赖公共库:

    dependencies {implementation project(':module_common')}

    而 common 组件依赖基础组件应该是用 api,因为把基础组件的能力传递给上层业务组件:

    dependencies {api project(':module_base')api project(':module_util')}

    多工程方案

    多工程就是每个组件都是一个工程,例如创建一个工程后 app 作为壳组件,它依赖 biz_home 运行,因此不需要 isModule 来控制独立调试,它本身就是一个工程可以独立调试。

    多工程的利弊就是和单工程相反的:

    • 利:做到职责完全拆分,其他项目复用更加方便,直接一行依赖引入。

    • 弊:修改后需要上传到Maven仓库,其他工程再次编译后才能感知到变化,多了上传和编译的时间。

    多工程组件依赖需要用到maven仓库。把每个组件的aar上传到公司内网的maven仓库,然后像这样去依赖:

    implementation 'com.xxx.xxx:module_common:1.0.0'

    我们把三方库统一放到 config.gradle 内管理:

    ext {    dependencies = [            "glide": "com.GitHub.bumptech.glide:glide:4.12.0",            "glide-compiler": "com.github.bumptech.glide:compiler:4.12.0",            "okhttp3": "com.squareup.okhttp3:okhttp:4.9.0",            "retrofit": "com.squareup.retrofit2:retrofit:2.9.0",            "retrofit-converter-gson"  : "com.squareup.retrofit2:converter-gson:2.9.0",            "retrofit-adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava2:2.9.0",            "rxjava2": "io.Reactivex.rxjava2:rxjava:2.2.21",            "arouter": "com.alibaba:arouter-api:1.5.1",            "arouter-compiler": "com.alibaba:arouter-compiler:1.5.1",            // our lib            "module_util": "com.sun.module:module_util:1.0.0",            "module_common": "com.sun.module:module_common:1.0.0",            "module_base": "com.sun.module:module_base:1.0.0",            "fun_splash": "com.sun.fun:fun_splash:1.0.0",            "fun_share": "com.sun.fun:fun_share:1.0.0",            "export_biz_home": "com.sun.export:export_biz_home:1.0.0",            "export_biz_me": "com.sun.export:export_biz_me:1.0.0",            "export_biz_msg": "com.sun.export:export_biz_msg:1.0.0",            "biz_home": "com.sun.biz:biz_home:1.0.0",            "biz_me": "com.sun.biz:biz_me:1.0.0",            "biz_msg": "com.sun.biz:biz_msg:1.0.0"    ]}

    这样方便版本统一管理, 然后在根目录的 build.gradle 内导入:

    apply from: 'config.gradle'

    最后在各自的模块引入依赖,比如在 module_common 中这么引入依赖即可。

    dependencies {api rootProject.ext.dependencies["arouter"]  kapt rootProject.ext.dependencies["arouter-compiler"]  api rootProject.ext.dependencies["glide"]  api rootProject.ext.dependencies["okhttp3"]  api rootProject.ext.dependencies["retrofit"]  api rootProject.ext.dependencies["retrofit-converter-gson"]  api rootProject.ext.dependencies["retrofit-adapter-rxjava2"]  api rootProject.ext.dependencies["rxjava2"]  api rootProject.ext.dependencies["module_util"]  api rootProject.ext.dependencies["module_base"]}

    个人觉得多工程适合"很大"的工程,每个业务组件可能都需要一个组开发,类似淘宝这样的app。但这只是针对业务组件来说的,业务基础组件和基础组件修改的频率不会很大,最好都是单工程上传至maven仓库来使用。本文的例子是为了方便所以把所有组件写到一起了,最好的方式就是把 fun_ 和 module_ 开头的组件都拆分成单工程独立开发,业务组件写到一个工程内。

    页面跳转

    做完组件之间的隔离后,暴露出来最明显的问题就是页面跳转和数据通信的问题。一般来说,页面跳转都是显示startActivity跳转,在组件化项目内就不适用了,隐式跳转可以用,但每个Activity都要写 intent-filter 就显得有点麻烦,如下所示:

    <activity android:name="com.liang.lib_video.videoplayer.VideoActivity">    <intent-filter>        <action android:name="com.intent.openVideoActivity"></action>        <category android:name="android.intent.category.DEFAULT" />    </intent-filter></activity>
    Intent intent = new Intent();intent.setClass("包名","Activity路径");intent.setComponent(new ComponentName("包名"));startActivity(intent);

    使用上述方式跳转会奔溃,提示在AndroidManifest文件中注册,这里需要注意的是,setClass/setComponent是APP的包名而不是所在module的包名。 可以参考最终生成的AndroidManifest文件。使用隐式跳转也可以先用resolveActivity进行验证。 如果不想要其他应用通过隐式打开,需要设置exported=false。

    隐式跳转是整个系统都能接收到,会相对想好性能,所以最好的方式还是用路由框架。

    实际上市面已经有比较成熟的路由框架专门就是为了组件化而生的,比如美团的WMRouter,阿里的ARouter等,本例使用 ARouter 框架,看下ARouter页面跳转的基本操作。

    首先肯定是引入依赖,以 module_common 引入ARouter举例,build.gradle 应该添加:

    android {defaultConfig {javaCompileOptions {       annotationProcessorOptions {          arguments = [AROUTER_MODULE_NAME: project.getName()]      }    }}compileOptions {      sourceCompatibility JavaVersion.VERSION_1_8      targetCompatibility JavaVersion.VERSION_1_8  }}dependencies {api rootProject.ext.dependencies["arouter"]  kapt rootProject.ext.dependencies["arouter-compiler"]}

    kapt注解依赖没有办法传递,所以我们不可避免得需要在每个模块都声明这些配置,除了 api rootProject.ext.dependencies["arouter"] 这行。然后需要全局注册 ARouter,我是在 module_common 统一注册的。

    class AppCommon: BaseApp{    override fun onCreate(application: Application) {        MLog.d(TAG, "BaseApp AppCommon init")        initARouter(application)    }    private fun initARouter(application: Application) {        if(BuildConfig.DEBUG) {            ARouter.openLog()            ARouter.openDebug()        }        ARouter.init(application)    }}

    接着我们在 module_common 模块内声明一个路由表用作统一管理路径。

    // RouterPath.ktclass RouterPath {    compaNIOn object {        const val APP_MAIN = "/app/MainActivity"        const val HOME_FRAGMENT = "/home/HomeFragment"        const val MSG_FRAGMENT = "/msg/MsgFragment"        const val ME_FRAGMENT = "/me/MeFragment"        const val MSG_PROVIDER = "/msg/MsgProviderImpl"    }}

    然后在MainActivity类文件上进行注解:

    @Route(path = RouterPath.APP_MAIN)class MainActivity : AppCompatActivity() {}

    任意模块只需要调用 ARouter.getInstance().build(RouterPath.APP_MAIN).navigation() 即可实现跳转。如果我们要加上数据传递也很方便:

    ARouter.getInstance().build(RouterPath.APP_MAIN)            .withString("key", "value")            .withObject("key1", obj)            .navigation()

    然后在MainActivity使用依赖注入接受数据:

    class MainActivity : AppCompatActivity() {    @Autowired    String key = ""}

    Arouter 实现组件间方法调用

    在 export_biz_msg 组件下声明 IMsgProvider,此接口必须实现 IProvider 接口:

    interface IMsgProvider: IProvider {    fun onCountFromHome(count: Int = 1)}

    然后在 biz_msg 组件里实现这个接口:

    @Route(path = RouterPath.MSG_PROVIDER)class MsgProviderImpl: IMsgProvider {    override fun onCountFromHome(count: Int) {      // 这里只是对数据进行分发,有监听计数的对象会收到        MsGCount.instance.addCount(count)    }    override fun init(context: Context?) {        // 对象被初始化时调用    }}

    在 biz_home 首页组件中发送计数:

    val provider = ARouter.getInstance().build(RouterPath.MSG_PROVIDER).navigation() as IMsgProviderprovider.onCountFromHome(count)

    可以看到其实和页面跳转的方式基本雷同,包括获取 Fragment 实例的方式也是这种。ARouter把所有通信的方式都用一种api实现,让使用者上手非常容易。

    组件化的消息通信方式选择

    广播

    作为Android中四大组件之一,Broadcast的职责是用于Android系统通信,但是普通的广播是全局广播,会造成安全泄露以及效率问题,如果只是在应用内部通知,可以使用更为高效的LocalBroadCast,相对于全局广播,本地广播只会在APp内部传播,不会造成隐私泄露,同时无法接受其他应用发送的广播,相对于全局广播来说更加高效。

    事件总线

    由于系统级别的广播传递比较耗时,消息通信科使用通过记录对象、使用监听者模式实现的事件总线框架,比如EventBus、LivaData等。

    Android开发组件化架构设计原理实例分析

    通过将消息的公用部分 ,如自定义消息的bean放入到baseMOdule下的单独模块来实现组件间消息的传递。组件化的数据库存储和消息通信的实现方式大同小异,都是将公用的东西放入到baseModule,如果内容比较多或者对于职责界限划分要求高的话可在base下新建一个DataBaseModule

    Application生命周期分发

    当 app 壳工程启动Application初始化时要通知到其他组件初始化一些功能。这里提供一个简单的方式。

    首先我们在 module_common 公共库内声明一个接口 BaseApp:

    public interface BaseAppInit {    boolean onInitCreate(Application application);    boolean onInitTerminal(Application application);}

    然后每个组件都要创建一个 App 类实现此接口,比如在某个业务组件:

    public class AudioInit implements BaseAppInit {    @Override    public boolean onInitCreate(Application application) {        return false;    }    @Override    public boolean onInitTerminal(Application application) {        return false;    }}

    剩下最后一步就是从 app 壳工程分发 application 的生命周期了,这里用到反射技术:

    val moduleInitArr = arrayOf(    "com.liang.lib_audio.app.AudioInit",    "com.liang.lib_audio.app.VideoInit",    "com.liang.lib_audio.app.LoginInit",)class App: Application() {    override fun onCreate() {        super.onCreate()        initModuleApp(this)    }    private fun initModuleApp(application: Application) {        try {            for(appName in moduleInitArr) {                val clazz = Class.forName(appName)                val module = clazz.getConstructor().newInstance() as BaseApp                module.onCreate(application)            }        }catch (e: Exception) {            e.printStackTrace()        }    }}

    我们只需要知道的每个实现 BaseApp 接口的类的全限定名并写到moduleInitArr数组里,然后通过反射获取 Class 对象从而获取构造函数创建实体对象,最后调用 BaseApp 的 onCreate 方法将 application 传入,每个Application生命周期的方法都可以通过这种方式传递。由于反射会消耗一定的性能,这个操作可以放在子线程,然后线程间通信。 当然,在每个module定义相对应的初始化方法,然后主module 调用也可以实现初始化,此处使用反射是为了最大程度的解耦。

    以上就是“Android开发组件化架构设计原理实例分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: Android开发组件化架构设计原理实例分析

    本文链接: https://lsjlt.com/news/341258.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Android开发组件化架构设计原理实例分析
      今天小编给大家分享一下Android开发组件化架构设计原理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。为什么需要组...
      99+
      2023-07-02
    • Android开发组件化架构设计原理到实战
      目录为什么需要组件化组件化和模块化模块化架构组件化架构组件化带来的优势组件化需解决的问题资源冲突解决AndroidManifest独立调试单工程方案多工程方案页面跳转Arouter ...
      99+
      2024-04-02
    • Hive架构设计及原理的示例分析
      这篇文章给大家分享的是有关Hive架构设计及原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Hive架构设计及原理1.什么是Hive:Hive是构建在Hadoop之上的数据仓库平台,可以结构化的数据文...
      99+
      2023-06-03
    • Android组件化架构开发--为什么要使用组件化?组件分层?组件路由的简单实现。
      文章目录 android组件化架构开发一.为什么要使用组件化1.1 单工程项目结构1.2 什么是组件化 二. 组件分层三. 组件化项目搭建流程3.1 创建业务组件3.2 创建基础组件3....
      99+
      2023-08-31
      android 架构
    • android组件化开发的原理是什么
      Android组件化开发的原理是将一个大型的应用程序拆分成多个独立的组件,每个组件包含自己的功能模块和界面,然后通过定义清晰的接口和...
      99+
      2023-10-22
      android
    • android开发之listView组件用法实例简析
      本文实例讲述了android开发之listView组件用法。分享给大家供大家参考,具体如下: 关于Android ListView组件中android:drawSelector...
      99+
      2022-06-06
      listview android开发 Android
    • vue组件化开发种vuex状态管理库的示例分析
      这篇文章主要介绍vue组件化开发种vuex状态管理库的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中...
      99+
      2024-04-02
    • Xamarin图表开发中OxyPlot组件构成的示例分析
      这篇文章主要为大家展示了“Xamarin图表开发中OxyPlot组件构成的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Xamarin图表开发中OxyPlot组件构成的示例分析”这篇文章...
      99+
      2023-06-04
    • java开发MVC三层架构上再加一层Manager层原理的示例分析
      这篇文章主要为大家展示了“java开发MVC三层架构上再加一层Manager层原理的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java开发MVC三层架构上再加一层Manager层原理...
      99+
      2023-06-25
    • 如何实现Android触摸事件分发的原理分析
      如何实现Android触摸事件分发的原理分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一:前言最近在学Android的触摸事件分发,我觉得网上说的太杂太乱,而且有很多博客都...
      99+
      2023-06-26
    • JS继承、工厂构造及原型设计模式实例分析
      这篇文章主要介绍“JS继承、工厂构造及原型设计模式实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JS继承、工厂构造及原型设计模式实例分析”文章能帮助大家解决问题。正文正是由于:原型链继承和构...
      99+
      2023-07-02
    • java开发分布式服务框架Dubbo原理机制的示例分析
      这篇文章给大家分享的是有关java开发分布式服务框架Dubbo原理机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言在介绍Dubbo之前先了解一下基本概念:Dubbo是一个RPC框架,RPC,即Re...
      99+
      2023-06-25
    • Android编程开发之Spinner控件用法实例分析
      本文实例讲述了Android编程开发之Spinner控件用法。分享给大家供大家参考,具体如下: 下拉列表 Spinner,Spinner是一个每次只能选择所有项的一个项的控件。...
      99+
      2022-06-06
      spinner Android
    • 基于Apache组件分析对象池原理的实现案例分析
      目录一、设计与原理1、基础案例2、接口设计1.1 PooledObjectFactory 接口1.2 ObjectPool 接口1.3 PooledObject 接口3、运行原理二、...
      99+
      2024-04-02
    • 深入解析Spring架构与设计原理-数据库的操作实现
      关于Spring JDBC 还是从Spring JDBC说起吧,虽然现在应用很多都是直接使用Hibernate或者其他的ORM工具。但JDBC毕竟还是很基本的,其中的JdbcTemplate就是我们经常使用...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作