組件化就是將我們的APP拆分成很多個模塊,每個模塊可以單獨運行,以便于開發(fā)維護和測試山涡,組件化中必不可少的是Gradle的配置唆迁,Gradle中使用的是Groovy語言,Groovy也是JVM語言的一種鳞溉,如果你熟悉kotlin熟菲,那么學(xué)習(xí)Groovy將更容易抄罕,這也得益于kotlin結(jié)合了各大語言的優(yōu)點于颖,引入了很多最新、最流行的概念
一做入、Groovy簡單上手
在AS中新建一個module,并在生成的Gradle中練習(xí)Groovy的基礎(chǔ)語法
1.定義變量
Groovy中變量的定義需使用def關(guān)鍵字翩剪,而且不需要強制指定類型
task testGroovy() {
def i = 1
println(i)
}
2.定義類
Groovy兼容Java前弯,定義類就和Java一樣了秫逝,類中成員變量會隱式生成get/set方法违帆,最后觀察打印方法的調(diào)用,在Groovy中方法調(diào)用可以省略"()"
task testGroovy() {
Project p = new Project("groovy", "1.0.0", "jvm")
// 打印版本號
println p.version
}
class Project {
String name
String version
String group
Project(String name, String version, String group) {
this.name = name
this.version = version
this.group = group
}
}
3.字符串
Groovy有三種定義字符串的方式
- 單引號
task testGroovy2() {
def s = 'hello'
println s
}
- 雙引號的畴,和kotlin一樣丧裁,可以使用$符取變量值
task testGroovy2() {
def s1 = 'hello'
def s2 = "$s1 groovy"
println s2
}
- 三個單引號煎娇,可以換行
task testGroovy3() {
def s = '''hello
groovy
is
simple
'''
println s
}
4.集合
- list
定義list時使用 "[ ]"
task testGroovy4() {
def list = ['one', 'two', 'three']
println list[1]
}
使用 "<<" 添加一個元素
task testGroovy4() {
def list = ['one', 'two', 'three']
list << 'four'
println list[3]
}
- map
map使用 ":" 隔開缓呛,區(qū)別key和value
task testGroovy5() {
def map = ['one': 1, 'two': 2, 'three': 3]
map << ['four': 4]
println map['four']
println map.four
}
5.閉包
熟悉kotlin的話杭隙,理解起來就簡單了痰憎,在使用上就是lambda表達式表示的變量,也就是函數(shù)類型變量
task testGroovy6() {
def print1 = { message ->
println "$message end"
}
print1 "hello"
}
二炬称、Gradle
Gradle主要分為兩個基本概念:項目(Project)與任務(wù)(Task)玲躯,可以用線程和方法的關(guān)系來理解,一個項目可以包含多個任務(wù)棘利,并且可以手動配置多個任務(wù)的調(diào)用鏈
1.Project
build.gradle文件在構(gòu)建時相當(dāng)于一個Project善玫,又稱為組件茅郎,常用的方法有:apply或渤、dependencies薪鹦、repositories、task
Project自帶屬性為:group奔害、name地熄、version
還可以使用ext离斩、gradle.properties來定義屬性
2.Task
任務(wù)是最小的工作單元,可以定義任務(wù)依賴于其他任務(wù),調(diào)用序列和執(zhí)行條件棋弥。常用方法有dependsOn顽染、doFirst、doLast
如下面例子尼荆,執(zhí)行doTwo任務(wù)時捅儒,會先執(zhí)行doOne任務(wù)
task doOne() {
println "doOne"
}
task doTwo() {
dependsOn doOne
println "doTwo"
}
結(jié)果:
doFrist巧还、doLast則可以指定任務(wù)中代碼塊的執(zhí)行順序:
task doOne() {
println "doOne"
}
task doTwo() {
dependsOn doOne
println "doTwo"
doLast {
println "doLast"
}
doFirst {
println "doFirst"
}
}
結(jié)果:
三麸祷、組件化
隨著app的迭代,業(yè)務(wù)越來越繁重喷面,為了讓業(yè)務(wù)可以分層惧辈,組件化出現(xiàn)了融求,經(jīng)過基礎(chǔ)組件的支撐,業(yè)務(wù)層組件可以單獨運行县昂,以便于新功能的開發(fā)于測試
1.新建業(yè)務(wù)module_a
業(yè)務(wù)module是可以單獨運行的倒彰,所以它的gradle使用的是com.android.application插件
將創(chuàng)建項目時的默認(rèn)的app module作為Application待讳,最后完整的app還是得通過該module來編譯仰剿,但此時并不能將module_a引入到app module中,找不到module_a
2.修改業(yè)務(wù)module_a的gradle配置
如果需要module_a能夠被引入琳彩,需要使用com.android.library插件露乏,但是它不能和com.android.application插件同時使用,怎么辦呢涂邀?答案是使用變量動態(tài)配置gradle
def isModule = true
if (isModule) {
apply plugin: 'com.android.library'
} else {
apply plugin: 'com.android.application'
}
apply plugin: 'kotlin-android'
manifest文件也是需要兩份,一份作為application的劳较,一份作為library的
src/main/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aruba.libmodule_a">
<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.ARouterApplication">
<activity
android:name=".ModuleAActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
src/main/manifest/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aruba.libmodule_a">
<application>
<activity android:name=".ModuleAActivity" />
</application>
</manifest>
在gradle中為他們配置兴想,根據(jù)變量加載不同的manifest文件:
android {
compileSdk 31
defaultConfig {
if (!isModule) {// application才有id
applicationId "com.aruba.libmodule_a"
}
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// 根據(jù)變量配置不同manifest
sourceSets {
main {
if (isModule) {
manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
}
3.依賴基礎(chǔ)組件實現(xiàn)module_a組件跳轉(zhuǎn)到app組件
現(xiàn)在我們可以在app module主界面中跳轉(zhuǎn)到module_a的Activity了
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun toModule(view: android.view.View) {
startActivity(Intent(this, ModuleAActivity::class.java))
}
}
但是moudle_a的Activity并不能跳轉(zhuǎn)到MainActivity捞镰,因為module_a并沒有引入app組件
解決方法:
3.1 在基礎(chǔ)base組件中緩存各個Activity的類岸售,利用緩存獲取需要跳轉(zhuǎn)的類
object ActivityCache {
val ActivityClzByName: MutableMap<String, Class<out Activity>> = mutableMapOf()
}
3.2 然后在module_a中依賴該base組件
3.3 最后在Application中將所有Activity的類放入緩存
class App : Application() {
override fun onCreate() {
super.onCreate()
ActivityCache.ActivityClzByName["main"] = MainActivity::class.java
ActivityCache.ActivityClzByName["module_a"] = ModuleAActivity::class.java
}
}
3.4 在ModuleAActivity中利用緩存map跳轉(zhuǎn)
class ModuleAActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_module_aactivity)
}
fun toMain(view: android.view.View) {
startActivity(Intent(this, ActivityCache.ActivityClzByName["main"]))
}
}
最后效果:
4.單獨運行moudle_a
改下moudle_a中g(shù)radle的變量值凸丸,就可以單獨運行moudle_a了