在介绍如何实现组件化的开始前,先介绍一下组件化与插件化
插件 : 指的是单一功能的组件,或是抽出来的widget等,如支付模块,路由模块,定位模块等。
模块 :指的是独立的业务模块,如常见App中的首页模块,直播模块,商城模块等。
区别 :组件化更偏向于功能的封装,插件化偏向于业务的模块。
一、库工程和module的区别
先来简单介绍一下Android依赖库和Android Project的区别,即 application和library的区别
1、build.gradle中的首行的区别(即标识是否是依赖库或完整工厂)
apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
2、build.gradle 中 applicationId 字段
android {
...
defaultConfig {
if (loginRunAlone.toBoolean()) {
applicationId "com.onexzgj.module.login"
}
...
}
}
- library 不需要 applicationID字段
- project 需要ApplicationId
3、清单文件的区别
- library 需要将本组件中4大组件的信息配置在清单文件中即可
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.onexzgj.module.login">
<application
android:theme="@style/AppTheme">
<activity android:name="com.onexzgj.module.login.LoginActivity">
</activity>
</application>
</manifest>
- project 需要配置完整application,权限、样式、4大组件等信息
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.onexzgj.module.login">
<application
android:name=".LoginApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name="com.onexzgj.module.login.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
二 、组件化需要解决的问题
1、统一管理项目开发环境,使用gradle
在project中将所有的使用到的配置进行集中配置,如何实现?
这里以按照我提交的上的示例为分析案例:
在根目录的gradle.properties中配置,相关的模块是否单独运行的配置,和相关的版本控制等信息包括是否组件进行集成调试的开关,如下所示:
//配置常量进行全局统一配置
compile_sdk_Version = 28
min_sdk_version= 21
target_sdk_version = 28
support_version=28.0.0
//module工程是否单独运行
liveRunAlone=false
loginRunAlone=false
forYouRunAlone=false
2、每一个组件都是一个完整的项目,所以组件也可以进行单独运行
改如何配置?
前面分析了library 和Project的区别,所以,想要让library单独运行,只需要将library中的几个特别注意的地方改为project即可
2.1 修改build.gradle的第一行
if (loginRunAlone.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
2.2 根据gradle.propertice配置是否需要applicationId字段
defaultConfig {
if (loginRunAlone.toBoolean()) {
applicationId "com.onexzgj.module.login"
}
...
}
只需要修改project下面的gradle.properties中的开关配置
3、实现组件之间的通信和数据传递,组件之间没有相互依赖,如何进行通信?
3.1 使用第三方的框架
除了使用第三方的组件化通信框架以外,自己如何实现组件之间的通信
这里实现模块之间的通信,可以使用好多第三方的开源框架(ARouter),如果不知道如何使用,请点击这里。
3.2 自己实现组件之间的通信
这里简单介绍一下如何实现?因为篇幅较长,等后期更新一篇单独实现文章
4、模块之间可以集成调试
在主Module中,根据gradle.properties中的配置,动态的进行依赖module,然后将模块最为library依赖到主Module中。
if (!liveRunAlone.toBoolean()) {
api project(':live')
}
if (!loginRunAlone.toBoolean()) {
api project(':login')
}
5、组件上下文使用 application的传递使用
包括初始化appliction的使用。
在公共模块中定义如下接口
public interface IAppComponent {
String[] compoment=new String[]{
"com.onexzgj.module.live.LiveApp",
"com.onexzgj.module.login.LoginApp"
};
void initlize(Application app);
}
在每个module中的App中都实现该接口,如下所示
public class LoginApp extends Application implements IAppComponent {
private LoginApp instance;
@Override
public void onCreate() {
super.onCreate();
initlize(this);
}
@Override
public void initlize(Application app) {
instance=this;
ServiceFactory.getInstance().setIloginService(new LoginService());
}
}
再来看看再BaseLibrary中的处理:
package com.onexzgj.onexlibrary;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.view.Gravity;
import com.onexzgj.onexlibrary.lib.IAppComponent;
/**
* Created by OnexZgj on 2018/9/1.
* <p>
* 全局Application
*/
public class GlobalApplication extends Application implements IAppComponent {
protected static Context context;
protected static Handler handler;
protected static int mainThreadId;
private static GlobalApplication mApp;
public static synchronized GlobalApplication getInstance() {
return mApp;
}
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
mApp = this;
handler = new Handler();
/**
* 初始化路由
*/
private void intARouter() {
// 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.init(this); // 尽可能早,推荐在Application中初始化
}
/**
* 获取上下文对象
*
* @return context
*/
public static Context getContext() {
return context;
}
@Override
public void initlize(Application app) {
try {
for (String com : compoment) {
Class<?> clazz = Class.forName(com);
Object o = clazz.newInstance();
if (o instanceof IAppComponent){
((IAppComponent)o).initlize(app);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
知道了以上信息后,接下来开启组件化之旅:
先来看看整体的模块和依赖关系:

各个module中的配置如下图所示

所有的module都依赖基础库(OnexLibrary) ,至于是否main工程要集成各个插件,则需要根据在gradle.properties 中配置的开关动态的编译
示例项目截图

示例项目已经上传至GitHub:
https://github.com/OnexZgj/ComponentProject
网友评论