Android组件化开发方案

11 篇文章 0 订阅
8 篇文章 1 订阅

Android组件化开发方案

Demo Github地址

Demo基础框架图
在这里插入图片描述

背景: 为什么要组件化开发?

1. 随着功能的增加代码越来越臃肿,到底项目调试越来越困难
2. 修改某个模块的代码,导致整个APP都会受到影响
3. 代码量大,编译速度也越来越慢

问题:进行组件化开发,需要解决哪些问题?

1. 每个模块既可以单独运行又可以作为库项目被引入到主模块中
2. 模块和模块之间代码和资源文件都需要隔离
3. 代码隔离后的组件和组件之间的通信问题

方案 (以Login模块为例,其他模块类似)

问题1(每个模块既可以单独运行又可以作为库项目被引入到主模块中)的解决方案

隔离AndroidManifest.xml文件

在Login模块的目录下面新建一个gradle.properties文件

添加一个变量asApp

#当为true时,表示作为一个单独的App运行,当为false时,表示作为一个库项目运行
asApp=false,

插件控制

if(asApp.toBoolean()){
    apply plugin: 'com.android.application'
}else {
    apply plugin: 'com.android.library'
}

applicationId 控制

  if (asApp.toBoolean()){
            applicationId "com.haifeng.example.login"
        }

Application 隔离

第一步,在公用模块创建Application基础类


public abstract class BaseApp extends Application {
    /**
     * Application 初始化
     */
    public abstract void onCreateModuleApp(Application application);


}

第二步,在模块中定义自己的Application继承BaseApp
class LoginApp :BaseApp(){

    override fun onCreate() {
        super.onCreate()
        onCreateModuleApp(this)
    }
    override fun onCreateModuleApp(application: Application?) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

}
第三步,在src/main/manifest/app/AndroidManifest.xml,注册LoginApp
    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:name=".LoginApp"
            android:theme="@style/login_AppTheme">
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

第四步主项目中创建MainApplication,初始化各个模块的Application
class  MainApplication:Application(){
    override fun onCreate() {
        super.onCreate()
        ARouter.openLog()     // 打印日志
        ARouter.openDebug()  // 开启调
        ARouter.init(this)
        initModuleApp()
    }


    /**
     * 初始化组件APP
     */
    fun initModuleApp() {
        for (moduleApp in AppConfig.moduleApps) {
            try {
                val clazz = Class.forName(moduleApp)
                val baseApp = clazz.newInstance() as BaseApp
                baseApp.onCreateModuleApp(this)
            } catch (e: ClassNotFoundException) {
                e.printStackTrace()
            } catch (e: IllegalAccessException) {
                e.printStackTrace()
            } catch (e: InstantiationException) {
                e.printStackTrace()
            }

        }
    }
}

隔离AndroidManifest.xml文件

按照图片的示例新建一个manifest目录,然后分别创建一个app目录和一个lib目录,然后在这两个目录里面分别存放 作为app运行的清单文件和作为lib运行的清单文件,如下图所示

在这里插入图片描述

  sourceSets {
        main {
            if (asApp.toBoolean()) {
                manifest.srcFile 'src/main/manifest/app/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/manifest/lib/AndroidManifest.xml'
            }
        }
    }

解决依赖问题

做完上面这些操作其实每个模块已经可以单独运行起来了,现在还需要解决一个问题,如果打包到主项目中,在gradle3.0的插件已经有实现了 runtimeOnly,在主项目的build.gradle的依赖中添加代码

dependencies {

 runtimeOnly project(path: ':login')
}

runtimeOnly的意思是login这个模块在编译期间对app模块不可见,只在运行期间可见

问题2(模块和模块之间代码和资源文件都需要隔离)

这个问题其实在问题1已经有解决,这里主要解决一下资源冲突的问题

在login模块中的build.gradle中添加配置


resourcePrefix "login_"

resourcePrefix表示约束,加上这个配置后,login模块的所有资源必须以login_ 开头

这些资源文件包括,颜色,尺寸,layout等

在这里插入图片描述

如图,加上login_后编译成功,不加上则报错

问题3(怎么解决组件化通信问题)

组件化通信下面几个关键方式

  • Activity通信

  • Service通信

  • 其他通信

关于Activity和Service通信方式可以参考Arouter,关于Aronter如何使用可以看看里面的文档

其他通信怎么实现?目前我想到了下面几种方式

  • 通过广播简历通信
  • 通过EventBus通信
  • 通过接口方式创建通信

广播和EventBus大家应该都比较熟悉,接下来我们重点介绍一下接口方式是怎么通信的

我们本次的例子是在主模块中调用Login模块的接口,显示一个Toast

第一步,在Base模块中创建LoginApi接口
interface LoginApi{
    fun showToast(toast:String)
}
第二步,在Base模块创建一个基础服务ApiService
class ApiService private  constructor(){
     var loginApi:LoginApi?=  null
        companion object{
            val  singleInstance:ApiService by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED){
                ApiService()
            }
        }



    fun  showToast(toast:String){

        loginApi?.showToast(toast)

    }
}

ApiService 是一个单例,提供模块间基础服务的通信,所有的模块服务都需要在ApiService注册

第三步,在Login模块中实现LoginApi
class LoginApiImpl :LoginApi {
    override fun showToast(toast: String) {
        Toast.makeText(LoginApp.app,toast,Toast.LENGTH_SHORT).show()
    }


}
第四步,注册Login模块服务
    override fun onCreateModuleApp(application: Application) {
        app=application

        ApiService.singleInstance.loginApi = LoginApiImpl()
    }

版本依赖统一管理

组件化开发还有一个很关键的一个,保证依赖库的统一性,所以我们需要在根目录的build.gradle文件里面定义变量来控制依赖库

 ext.versions = [
            'minSdkVersion'   : 15,
            'targetSdkVersion': 28,
            'versionCode'     : 1,
            'arouter_version' : '1.5.0',
            'constraint_layout_version':'1.1.3',
            'androidPlugin':'3.4.1'
    ]


    ext.deps = [
            //plugins
            android  : [
                    'gradlePlugin': "com.android.tools.build:gradle:${versions.androidPlugin}",
            ],

            //google support
            'support': [
                    'compat'     : "com.android.support:support-compat:${versions.supportLibrary}",
                    'design'     : "com.android.support:design:${versions.supportLibrary}",
                    'v7'         : [
                            'appcompat'   : "com.android.support:appcompat-v7:${versions.supportLibrary}",
                            'recyclerView': "com.android.support:recyclerview-v7:${versions.supportLibrary}",
                            'cardView'    : "com.android.support:cardview-v7:${versions.supportLibrary}",

                    ],
                    'v4'         : [
                            'support_v4': "com.android.support:support-v4:${versions.supportLibrary}"
                    ],
                    'annotations': "com.android.support:support-annotations:${versions.supportLibrary}",

                    'multidex'   : "com.android.support:multidex:1.0.1",
                    'constraint' :"com.android.support.constraint:constraint-layout:1.1.3",
                    'test'       : [
                            'runner': 'com.android.support.test:runner:1.0.1',
                            'rule'  : 'com.android.support.test:rules:1.0.1'
                    ],
            ],






    ]

在依赖中添加

 implementation deps.support.compat.constraint
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值