组件化
组件化的一般结构
业务组件层
业务组件层在创建Module时一般使用 Phone&Tablet 类型的,这个需要单独的去进行调试,这种类型的可以单独的进行调试,Phone&Tablet这种可以在 library 和 application之间进行转换。
功能组件层
功能组件层主要是将我们的一些基础组件进行封装,在创建Module时一般使用Android Library 这种类型,这种不能单独的进行调试。但是如果需要进行单独调试的话就可以创建 Phone&Tablet 类型的。不管是哪种类型的,在最终打包apk的时候都要将其转化为library。
基础组件层
实现基本功能,功能组件层需要依赖基础组件层,在这一层一般都是一些简单的功能,一般不需要进行单独的调试,所以一般都是Android Library这种类型的。
组件化的框架搭建
ext {
android = [
compileSdkVersion : 31,
buildToolsVersion : 28,
applicationId :"com.example.moudle",
minSdkVersion :21,
targetSdkVersion :31,
versionCode :1,
versionName :"1.0",
testInstrumentationRunner :"androidx.test.runner.AndroidJUnitRunner"
]
androidxDeps = [
"appcompat": 'androidx.appcompat:appcompat:1.1.0',
"material": 'com.google.android.material:material:1.1.0',
"constaraintlayout": 'androidx.constraintlayout:constraintlayout:1.1.3',
]
commonDeps = [
"arouter_api" : 'com.alibaba:arouter-api:1.5.1',
"glide" : 'com.github.bumptech.glide:glide:4.11.0'
]
annotationDeps = [
"arouter_compiler" : 'com.alibaba:arouter-compiler:1.5.1'
]
retrofitDeps = [
"retrofit" : 'com.squareup.retrofit2:retrofit:2.9.0',
"converter" : 'com.squareup.retrofit2:converter-gson:2.9.0',
"rxjava" : 'io.reactivex.rxjava2:rxjava:2.2.20',
"rxandroid" : 'io.reactivex.rxjava2:rxandroid:2.1.1',
"adapter" : 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
]
androidxLibs = androidxDeps.values()
commonLibs = commonDeps.values()
annotationLibs = annotationDeps.values()
retrofitLibs = retrofitDeps.values()
}
android 是一些版本号的一些东西,中间是一些依赖库的导入,最后这四行是对前面的几个依赖库的封装。
在这个application中的gradle.properties这个文件中定义isDebug变量,如果这个值为true,则这个module可以单独的运行,就能够对这个模块单独的进行调试。如果为false,则这个module就是不能单独的运行,就只能依赖于app,它就相当于一个依赖库,只能依赖在这个app上面。
isDebug = false
这个isDebug是非常重要的一个变量,它控制了这个组件是否能够单独的运行。
在module下的build.gradle需要改变plugin
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application' //需要单独调试的
} else {
apply plugin: 'com.android.library' //不能单独运行,相当于一个依赖库,
}
还需要在buildTypes中定义以下代码:
sourceSets{
main{
if(isDebug.toBoolean()){
manifest.srcFile 'src/main/Debug/Androidmanifest.xml'
}else{
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
解释一下,这里声明了manifest文件是使用的哪一种。DeBug版本使用的和app使用的是一样的,但是在依赖的版本使用的是只有一个四大组件的声明,没有application的一些声明。
debug版本的Manifest.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.module">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Moudle">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
依赖库版本的Manifest.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.module">
<application>
<activity android:name=".MainActivity"/>
</application>
</manifest>
还需要导入依赖库:
api rootProject.ext.androidxLibs
api rootProject.ext.commonLibs
api rootProject.ext.annotationLibs
在这使用api导入依赖库。
在app中的build.gradle中导入所依赖的组件,就能够将组件进行依赖在这个app上面,使这个”空壳APP“组装成为一个真正的App。
implementation project(":module")
这样就大体将一个组件化的框架搭建起来了。
当要进行调试时,将isDebug改为true之后,一定要记得sync。
api和implementation导入依赖的区别
implementation 表示依赖,即 只依赖不打包进来。
api 表示打包,即 不仅依赖还打包进来,这样上层就不用重复依赖。
注意:这里的打包是便于理解,是指打包依赖关系而不是打包源代码,也就是说将依赖暴露给上层。
组件间的通信
在没有使用组件化开发之前,活动与活动之间是能够通过Intent去相互交流,但是使用了组件化之后,就不能够去使用Intent进行活动之间的交流,所以就需要引入ARouter去进行组件之间的通信。
ARouter
ARouter是用于进行组件之间的通信。支持模块间的路由、通信、解耦。它可以实现组件间的路由功能。路由是指从一个接口上收到数据包,根据数据路由包的目的地址进行定向并转发到另一个接口的过程。这里可以体现出路由跳转的特点,非常适合组件化解耦。
ARouter的配置
在defaultConfig中导入:
javaCompileOptions{ //配置ARouter
annotationProcessorOptions{
arguments = [AROUTER_MODULE_NAME:project.getName()]
}
}
导入ARouter的注解器:
annotationProcessor rootProject.ext.annotationLibs
上面就是ARouter的一些简单配置,这需要在每一个模块下都需要配置,配置玩这些就能够使用ARouter了。
ARouter的使用
ARouter在使用之前需要先进行初始化操作,因为使用ARouter可能需要对每一个活动进行操作,所以我们需要在每一个模块之前进行初始化,所以就需要在Application层去进行初始化。所以在创造活动时就需要进行初始化ARouter。
import android.app.Application;
import com.alibaba.android.arouter.launcher.ARouter;
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (isDebug()) {
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(this); // 尽可能早,推荐在Application中初始化ARouter
}
private boolean isDebug() {
return BuildConfig.DEBUG;
}
}
在这里BaseApplication继承了Application,重写了onCreate()方法,在这里重写了Application的方法,就需要在AndroidManifest.xml文件中进行声明Application的name,所以需要在Application中加上下面这句话:
android:name=".BaseApplication"
前面是所有的准备工作,现在就开始正式的使用ARouter了,如果需要在activity、service、fragment等等之间进行跳转,就需要使用@Route(path = “/xx/xx”),这里的path是一个跳转路径,/xx/xx是一个二级目录。
这里需要注意:同一个组件的一级目录可以相同,但是不同组建的一级目录不能相同。
app目录下的MainActivity:
@Route(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.buttonMain);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ARouter.getInstance().build("/module/MainActivity2").navigation();
}
});
}
}
module目录下的MainActivity2:
@Route(path = "/module/MainActivity2")
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
}
由以上代码可知,在MainActivity中点击Button之后,就会跳转到MainActivity2活动中去。如果路径填写不正确,将会弹出Toast提醒。
ARouter.getInstance().destroy();
上面这行代码可以写在Application生命周期的onTerminate( )里面。上面这行代码是解绑释放资源的,有解绑,就需要有注入,因为这每一个活动都是添加在一个集合上面的,所以在每一个活动中需要添加:(ARouter相当于一个容器,只有向里面注入内容,才能够拿取里面的内容)
ARouter.getInstance().inject(this);
如果需要在Activity之前进行跳转的时候需要传递数据,就需要使用@Autowired()注解。
@Route(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.buttonMain);
ARouter.getInstance().inject(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ARouter.getInstance().build("/module/MainActivity2")
.withString("name", "android")
.withDouble("d", 10.1)
.navigation();
}
});
}
}
@Route(path = "/module/MainActivity2")
public class MainActivity2 extends AppCompatActivity {
@Autowired()
String name;
@Autowired(name = "d")
double aDouble;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ARouter.getInstance().inject(this);
Log.d("TAG", "onCreate: " + name + " + " + aDouble);
}
}
上面这两段代码还是之前跳转活动的代码,在这如果不在注解中写name参数,就需要将变量名写成和name值相等,但是我建议还是写上name参数,这样就避免了可能会发生的一些错误。(在传输数据时,必须将此活动进行注入ARouter)