前言

最近在练习多模块,基本上是从0开始的,中途遇到了好多问题报错等等,故开个这篇文章记录总结一下,以防后面继续踩坑qaq。

是用的玩Android,基本上是把寒假写的东西搬了过来重构了一下,技术上没什么高级的。。。

github项目地址:https://github.com/generalio/WanAndroidMulti

相较于寒假的优化如下:

  • 对网络是否链接进行了判断

  • 使用MVVM+Retrofit+RxJava+Jetpack的结构进行开发(不敢使用协程,还不太熟悉)

  • 使用了paging3进行分页加载

  • 搜索页面能进行模糊搜索

  • 把整体页面套了个androidx.coordinatorlayout.widget.CoordinatorLayout,在列表进行滑动时能有很好的加载逻辑

文章的收藏功能懒得写了,太麻烦了并且容易出一些奇奇怪怪的bug。

多模块构建

多模块,就是将自己的app的许多界面或者不同的功能拆成一个个单个的模块,将项目进行拆分,解耦。

多模块分为lib,module,api(没怎么用过)这几个模块类型。

新建模块

新建lib模块

这里我们选择Android LibraryModule name改为lib_xxx,注意还要将Package name.lib_xxx改成.lib.xxx,这样就新建好了一个lib模块了。

然后在主模块的build.gradle.kts中依赖一下就好了:

1
implementation(project(":lib_base"))

新建module模块

步骤与上面一样,但是我们要选择第一个Phone & Tablet,然后进行一些改动:

删除res中的不必要的东西:

然后删除string.xml中的app_name.修改AndroidMainfest.xml:

1
2
3
4
5
6
<application>
<activity
android:name=".TestActivity"
android:exported="true">
</activity>
</application>

最后再build.gradle.kts中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
plugins {
//alias(libs.plugins.android.application) 这是原来的
alias(libs.plugins.kotlin.android)
id("com.android.library") //换成这个library
}
android {
namespace = "com.generals.module.main"
compileSdk = 35

defaultConfig {
//applicationId = "com.generals.module.main" 删除掉
minSdk = 30
targetSdk = 34
//versionCode = 1 删除掉
//versionName = "1.0" 删除掉

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}

这样就好了,然后同样在主模块中依赖一下:

1
implementation(project(":module_test"))

这样就构建好了module模块。

总的来说,lib模块通常是存放一些基类和工具类,比如baseactivity,basefragment以及一些工具的封装等等。

module模块通常就是一个界面,比如main,login等,在这些模块中我们通常要将lib_base依赖进去。

模块间的通信

模块间的通信,同一层级中的几个模块通常不会互相依赖,所以不能直接进行通信,于是我们用到了Arouter。

ARouter 是阿里2017年开源的页面路由框架,官方对这个框架的定义是 ARouter 是阿里巴巴开源的 Android 平台中对页面、服务提供路由功能的中间件,提倡的是简单且够用。

导入依赖:

1
2
arouter-api = { module = "com.alibaba:arouter-api", version.ref = "arouter" }
arouter-compiler = { module = "com.alibaba:arouter-compiler", version.ref = "arouter" }

这是在gradle/libs.versions.xml下的依赖统一管理方式。

在模块中添加依赖和配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
plugins {
//alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.android.library")
kotlin("kapt")
}

kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.name)
}
}
...
dependencies {

...
implementation(libs.arouter.api)
kapt(libs.arouter.compiler)

implementation(project(":lib_base"))
}

初始化SDK,在你的全局Application中(如BaseApp.kt):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class BaseApp : Application() {
companion object {
@SuppressLint("StaticFieldLeak")
lateinit var context : Context
}

private val isDebug = true

override fun onCreate() {
super.onCreate()

//获取全局context
context = applicationContext

//Arouter的初始化
if(isDebug) {
ARouter.openLog()
ARouter.openDebug()
}
ARouter.init(this)
}
}

添加注解:

1
2
3
4
5
6
7
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/test")
class TestActivity : AppCompatActivity() {
...
//获取数据
var key3 = getIntent().getStringExtra("key3")
}

发起路由操作:

1
2
3
4
5
6
7
8
9
10
11
12
// 1. 应用内简单的跳转
ARouter.getInstance().build("/test/activity").navigation()
// 2. 跳转并携带参数
ARouter.getInstance().build("/test/activity")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.withBundle("bundle", bundle)
.navigation()
// 获取Fragment
val fragment:Fragment = (Fragment)
ARouter.getInstance().build("/test/fragment").navigation()

还有一些拦截器的操作(比如跳转时处理是否登录),就不多介绍(感觉也不太常用)。

在使用Arouter时,打包编译时可能会报错:

提示导入了support包与现在的冲突了,这是Arouter导入时会自动引入的东西,只需要在根目录下的gradle.properties文件下加入下面的代码:

1
2
3
# Arouter中包含support包,使用该选项后Android插件会通过重写第三方库的二进制文件,自动将这些库迁移为AndroidX
# https://developer.android.com/jetpack/androidx/migrate
android.enableJetifier=true

这样就解决了。

然后剩下的就跟普通的差不多了,编译打包时全量打包就好了不用单模块调试。单模块调试可能出些奇奇怪怪的问题(因为你这个模块依赖了些其他模块,而单模块调试不会将这些模块导进去)。