Android 项目组件化

来源:互联网 发布:photoshop cc mac版本 编辑:程序博客网 时间:2024/04/30 09:03

问题

1、单一工程的业务模块耦合度太高,不能快速适应快速变化的业务需求 2、进行简单修改也必须花4、5分钟重新打包编译整个程序3、功能测试和系统测试每次都要进行4、团队协同开发存在较多的冲突,需要花更多时间去协调;5、不能灵活的对业务模块进行配置和组装;

方案

项目组件化,将不同模块分成不同组件。

代码分“组件”
App壳工程:负责管理各个业务组件,和混淆、打包apk,不执行具体业务
业务组件:根据公司具体业务而独立形成一个的工程
功能组件:提供开发APP的某些基础功能,例如图片加载、线程池管理、打印日志等

开发分“模式”
集成开发模式:此模式下,App壳工程囊括所有组件组成一个 App,业务组件作为library存在
组件开发模式:此模式下,每个业务组件工程能最为 App 独立运行

建议:
App壳工程不进行任何具体业务,使用业务组件 Main 来实现APP启动页面、主界面等业务
业务组件之间不要相互依赖,相互之间的 Activity 调用借助 ActivityRouter 来实现
共用的功能组件,用来管理全程序都需要功能和对象基类。如:Application 基类。

流程

在 Android Studio 借助 Gradle 自动构建工具实现项目组件化。

组件模式、继承模式转换开关

在项目根目录的文件 gradle.properties 增加常量isDebug

isDebug = true

每个组件工程借助开关来转换工程属性。编辑组件的build.gradle

// 组件开发模式,作为一个单独的应用if (isDebug.toBoolean()) {    apply plugin: 'com.android.application'}// 继承开发模式,作为一个libraryelse {    apply plugin: 'com.android.library'}

多组件 Manifest 合并

在集成开发模式下,所有的 AndroidManifest.xml 都要合并在壳工程中,如果将每个组件的 Application 和 LaunchActivity 和在一起会产生冲突。
业务组件需要两个 AndroidManifest.xml,一个集成开发模式用,一个组件开发模式时使用。

图片1

    sourceSets {        main {            // 组件开发模式            if (isDebug.toBoolean()) {                manifest.srcFile 'src/main/debug/AndroidManifest.xml'            }            // 集成开发模式            else {                manifest.srcFile 'src/main/AndroidManifest.xml'                // 排除 debug 文件夹中的所有 Java 文件                java {                    exclude 'debug/**'                }            }        }    }

业务组件 单独运行时,需要获取数据和初始化服务,需要自己的 Application 等类,但在作为 Library 时,又不需要这些类。
建立 debug 包,将组件开发模式下才需要的类放在其中,并在集成开发模式时排除。
因为最后会排除,所以业务组件不能持有 debug 保重对象的强引用。

图片2

组件开发模式下的 AndroidManifest.xml,要声明 Application 和 LaunchActivity,并且设置 App 的名字、图标等属性

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="org.module.main">    <application        android:name=".debug.Application4Main"        android:allowBackup="true"        android:label="@string/app_name"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

集成开发模式下的 AndroidManifest.xml,为了方便声明此组件下所有 Activity 的主题外,其他的不用声明

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="org.module.main">    <!-- 不能设置 Application 、名称、图标等属性,避免与壳工程重复 -->    <!-- 业务组件:不能设置 Launch Activity-->    <application android:theme="@style/AppTheme">        <!--        如果是 Main 组件        声明 Launch Activity 作为整个程序的 Launch Activity        -->        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

资源合并

图片等资源名重复会报错,如:A组件和B组件都ic_back.png的文件,在集成开发模式下回编译出错。
最简单的解决办法就是在项目中约定资源文件命名约束,如以组件名为资源名开头。

全局Context

Android 程序启动后会建立且只有建立一个 Application 对象。在组件开发模式下,肯定使用了正对组件声明的 Application,切换为集成开发模式后,所有的组件都使用 App 壳工程建立的 Application 对象。在组件开发模式下,肯定使用了正对组件声明的。
为了不出问题,要保证业务组件在集成开发模式下也能正确获取到 Application。
建立 BaseApplication ,业务组件工程和App壳工程声明的 Application 都继承自 BaseApplication 就行了。

组件间调用

业务组件A 想调起 业务组件B 的 Activity,肯定不能让 A 导入 B 的依赖,因为项目组件化的目的就是解决模块之间的强依赖问题。

1.) 使用Uri来进行跳转,Activity声明设置

        <activity android:name=".MainViewActivity">            <intent-filter>                <!-- 为了明确的指向性,这里可设置专属action,如:android.tryout.action.MainViewActivity -->                <action android:name="android.intent.action.VIEW" />                <category android:name="android.intent.category.DEFAULT" />                <!-- 支持 JS 调起界面 -->                <category android:name="android.intent.category.BROWSABLE" />                <data                    android:host="view.main"                    android:scheme="myscheme" />            </intent-filter>        </activity>

在程序捏调起此界面

Uri uri = Uri.parse("myscheme://view.mian");            Intent intent = new Intent(Intent.ACTION_VIEW, uri);            startActivity(intent);

需要注意的是,使用URL启动Activity默认是FLAG_ACTIVITY_NEW_TASK启动模式,所以可能存在URL启动的Activity跟应用已启动的Activity不再同一个堆栈的现象。
需要我们在manifest中将Activity多配置一个taskAffinity属性,约束URL启动的Activity与应用自身的启动的Activity在同一个堆栈中。

2.) 可使用 ActivityRouter 框架,使用 RUL 来进行 Activity 的跳转
ActivityRouter Github

好处

不限制开发框架(MVP、MVC、MVVM),可自由选择
方便单元测试
代码模块耦合降低,降低项目的维护难度
加快编译速度,提高开发效率
团队协同开发冲突降低
为公司节省了经营成本

组件化 项目 链接

原创粉丝点击