前言
盛年不重来,一日难再晨。及时宜自勉,岁月不待人
什么是组件化,为什么需要组件化?
早期单一分层模式
问题一:无论分包怎么做,随着项目增大,项目失去层次感,后面接手的人扑街
问题二:包名约束太弱,稍有不注意,就会不同业务包直接互相调用,代码高耦合 问题三:多人开发在版本管理中,容易出现代码覆盖冲突等问题
组件化意义
不相互依赖,可以相互交互,任意组合,高度解耦,自由拆卸,自由组装,重复利用,分层独立化
集成环境/组件环境自动部署配置
抽取公共Gradle
创建config.gradle
编写config.gradle内容
//config.gradle
ext{
androidID = [
compileSdk : 31 ,
applicationId :"com.rengy.gradledemo",
minSdk : 21,
targetSdk :31,
versionCode: 1,
versionName:"1.0",
testInstrumentationRunner:"androidx.test.runner.AndroidJUnitRunner"
]
}
在build.gradle配置
配置第三方组件
//config.gradle
dependenciesID=[
"appcompat":"androidx.appcompat:appcompat:1.2.0",
"material":"com.google.android.material:material:1.3.0",
"constraintlayout":"androidx.constraintlayout:constraintlayout:2.0.4"
]
使用
dependencies {
//k:key,v:value
//for循环遍历
dependenciesID.forEach{k,v -> implementation v}
}
通过gradle控制测试环境或正式环境
//在config.gradle添加一个变量
ext{
//正式环境 和 测试环境
isRelease = false
//正式环境 和 测试环境 的url配置
url=[
"debug":"https://10.10.10.100/debug",//如果打包apk是debug走这个
"release":"https://10.10.10.100/release"//如果打包apk是release走这个
]
...
}
然后在build.gradle(app)中配置
buildTypes {
debug{
buildConfigField("String","debug","\"${url.debug}\"")
}
release {
buildConfigField("String","release","\"${url.release}\"")
...
}
}
然后就可以在activity中调用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
BuildConfig.debug
...
}
}
会出现刚才配置的url
同理把配置的isRelease也拿出来
defaultConfig {
...
buildConfigField("boolean","isRelease",String.valueOf(isRelease))
}
通过isRelease控制,其他组件能否独立运行
改为true后不能单独运行
组件化中子模块交互方式(非Arouter版)
方式一:使用EventBus的方式,缺点是:EventBean维护成本太高,不好去管理:
方式二: 使用广播的方式,缺点是:不好管理,都统一发出去了
方式三: 使用隐士意图方式,缺点是:在AndroidManifest.xml里面配置xml写的太多了
方式四: 使用类加载方式,缺点就是,容易写错包名类名,缺点较少
方式五: 使用全局Map的方式,缺点是,要注册很多的对象
(讲一下方式四,方式五)
类加载方式
public void jump(View view) {
// todo 方式一 类加载
// 类加载跳转,可以成功。维护成本较高且容易出现人为失误
try {
Class targetClass = Class.forName("com.目标activity路径");
Intent intent = new Intent(this, targetClass);
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
全局Map方式
首先创建RecordPathManager
**
* 全局路径记录器(根据子模块进行分组)
*
* 组名:app,order,personal
* 详情order=[Order_MainActivity,Order_MainActivity2,Order_MainActivity3]
*
*/
public class RecordPathManager {
/**
* 先理解成 仓库
* group: app,order,personal
*
* order:
* OrderMainActivity1
* OrderMainActivity2
* OrderMainActivity3
*/
private static Map<String, List<PathBean>> maps = new HashMap<>();
/**
* 将路径信息加入全局Map
*
* @param groupName 组名,如:"personal"
* @param pathName 路劲名,如:"Personal_MainActivity"
* @param clazz 类对象,如:Personal_MainActivity.class
*/
public static void addGroupInfo(String groupName, String pathName, Class<?> clazz) {
List<PathBean> list = maps.get(groupName);
if (null == list) {
list = new ArrayList<>();
list.add(new PathBean(pathName, clazz));
// 存入仓库
maps.put(groupName, list);
} else {
// 存入仓库
maps.put(groupName, list);
}
// maps.put(groupName, list);
}
/**
* 只需要告诉我,组名 ,路径名, 就能返回 "要跳转的Class"
* @param groupName 组名 oder
* @param pathName 路径名 OrderMainActivity1
* @return 跳转目标的class类对象
*/
public static Class<?> startTargetActivity(String groupName, String pathName) {
List<PathBean> list = maps.get(groupName);
if (list == null) {
Log.d(Config.TAG, "startTargetActivity 此组名得到的信息,并没有注册进来哦...");
return null;
}
// 遍历 寻找 去匹配 “PathBean”对象
for (PathBean pathBean : list) {
if (pathName.equalsIgnoreCase(pathBean.getPath())) {
return pathBean.getClazz();
}
}
return null;
}
}
然后在application中注册
public class AppApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
// 如果项目有100个Activity,这种加法会不会太那个? 缺点
RecordPathManager.addGroupInfo("app", "MainActivity", MainActivity.class);
RecordPathManager.addGroupInfo("order", "Order_MainActivity", Order_MainActivity.class);
RecordPathManager.addGroupInfo("personal", "Personal_MainActivity", Personal_MainActivity.class);
}
}
使用
public void jump(View view) {
// todo 方式二 全局Map
Class<?> targetActivity =
RecordPathManager.startTargetActivity("personal", "Personal_MainActivity");
startActivity(new Intent(this, targetActivity));
}
后记
全篇完