Android元件化的基本操作+ARouter的基本使用(動圖演示)
一、Android元件化的基本操作
Android元件化是指將專案劃分為多個模組,並且每個模組可以單獨的作為app執行。有利於不同業務的解耦,並且可以提高編譯速度,提高協作開發的效率。
1.從新建專案開始吧,取個簡單的名字:Component:
建好之後長這樣:
2.既然是要分模組,那我們先建幾個模組:
本例中,我們新建了Base模組,First模組,Second模組,Base模組用來放置每個模組都要用到的公共內容,First模組和Second模組是功能模組。新建專案時自動生成的app模組作為一個殼模組,用來整合其他模組。
新建的模組中有很多測試的檔案,如圖:
筆者從事開發安卓一年多,尚未接觸過單元測試,所以我們先把和測試有關的檔案刪掉,程式看起來會更加的簡潔。(當然如果讀者需要這些測試檔案,將它們保留即可。)module中的versionCode和versionName也是可以刪除的。
先切換到Project模式,再刪除每個模組的androidTest資料夾、test資料夾以及build.gradle中測試有關的內容。(如果不切換到Project模式,直接在Android模式下刪除androidTest資料夾和test資料夾的話,也可以刪除這兩個資料夾中的內容,但是無法刪除這兩個資料夾,就會導致有兩個空資料夾,雖然對程式碼沒有任何影響,但是筆者是一個程式碼強迫症患者,還是想把它們徹底刪除...),將module中的versionCode和versionName也刪除,只保留app模組中的versionCode和versionName。
3.gradle的統一管理
首先在專案根目錄的build.gradle中,新增Sdk版本配置和依賴庫的版本資訊:
ext { cfg = [ compileSdk : 27, minSdk : 15, targetSdk : 27, versionCode : 1, versionName : "1.0" ] libs = [ support : "com.android.support:appcompat-v7:27.1.1", constraintLayout: "com.android.support.constraint:constraint-layout:1.1.0" ] }
添加了之後,就可以在模組的build.gradle中,使用cfg.compileSdk、libs.support等變量了。這裡的cfg、libs、compileSdk、support都是變數名,名字可以任取。
3.1.我們把各個模組需要依賴的公共庫新增到base模組的build.gradle中。
此時,base的build.gradle完整程式碼如下:
apply plugin: 'com.android.library' android { compileSdkVersion cfg.compileSdk defaultConfig { minSdkVersion cfg.minSdk targetSdkVersion cfg.targetSdk } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { api fileTree(dir: 'libs', include: ['*.jar']) api libs.support api libs.constraintLayout }
3.2.然後在first模組和second模組的build.gradle中,新增base模組依賴。
此時,first模組和second模組的build.gradle相同,如下:
apply plugin: 'com.android.library' android { compileSdkVersion cfg.compileSdk defaultConfig { minSdkVersion cfg.minSdk targetSdkVersion cfg.targetSdk } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':base') }
3.3.在app模組的build.gradle中,新增base模組,first模組,second模組的依賴。
此時,app模組下的build.gradle程式碼如下:
apply plugin: 'com.android.application' android { compileSdkVersion cfg.compileSdk defaultConfig { applicationId "com.simple.component" minSdkVersion cfg.minSdk targetSdkVersion cfg.targetSdk versionCode cfg.versionCode versionName cfg.versionName } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':base') implementation project(':first') implementation project(':second') }
注意base中新增依賴時需要使用api關鍵字,不能使用implementation關鍵字。因為implementation關鍵字引入的庫是對外不開放的。(對外不開放的意思是指:在其他模組中引入base模組後,無法使用base模組中implementation引入的依賴庫;api關鍵字引入的庫是對外開放的。)
4.要讓first模組能夠單獨執行,需要first模組有一個啟動Activity,並且需要將first模組下的build.gradle中的apply plugin: 'com.android.library'改為apply plugin: 'com.android.application'
4.1.那麼我們就來試試吧,做一些簡單的修改,讓first模組單獨執行起來:
先是新建了一個Activity,注意這裡命名不能和其他模組重複,所以我們帶上模組名做區分,命名為FirstMainActivity。然後將FirstMainActivity作為啟動Activity,然後將first模組下的build.gradle中的apply plugin: 'com.android.library'改為apply plugin: 'com.android.application',由於first模組變成了一個單獨的可執行模組,所以app模組中不能將他作為庫依賴進來了,所以我們先將app模組下的implementation project(':first')註釋掉
切換到first模組執行:
4.2這時候會遇到崩潰,開啟Log日誌看到如下資訊:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.simple.first/com.simple.first.FirstMainActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
指的是Activity必須有一個主題,那麼我們就來給FirstMainActivity設定一個主題:
我們注意到,app模組下是有一個AppTheme主題的,我們把app模組下的styles檔案和AppTheme中使用到的colors檔案都移動到base模組下的values資料夾中,然後在first模組的AndroidManifest中,給application標籤新增主題:android:theme="@style/AppTheme"(也可以只給FirstMainActivity新增主題,在application標籤中新增主題會給first模組下所有的Activity都新增這個主題)。這時候再執行first模組就沒有問題了。
app會使用預設的圖示,app名字為包名:
4.3.如果要自己設定app的名字和圖示等屬性,照著app模組下AndroidManifest中的application標籤中依樣畫葫蘆即可:
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">注:
allowBackup是指此app是否允許備份使用者資料,如果不需要的話最好關閉,網上說有開啟它有安全風險
icon是指應用圖示
roundIcon是指應用圓形圖示
label是指應用名稱
supportsRtl是指是否支援從右到左佈局(Rtl是right-to-left的縮寫),舉個例子:如果在佈局中使用了marginLeft屬性,AndroidStudio就會提示我們:
可以看到,AndroidStudio建議我們增加android:layout_marginStart="16dp",這是由於有的國家是從右到左寫字的(比如我們的阿拉伯兄弟),如果supportsRtl設定為true,佈局中設定android:layout_marginStart="16dp",那麼對於從右到左寫字的國家,佈局就會變成從右往左,方便他們使用。
5.通過第4點我們已經學會了怎麼讓模組單獨執行,但是我們想要達到的效果是:讓一個模組隨時可以單獨執行,也可以隨時切換成總app的一個模組方便打包。接下來,我們通過一個標誌位來處理這兩種情況。
5.1.先在first模組的java資料夾下,新建debug資料夾,將第4步中first模組下的AndroidManifest複製到debug資料夾中,再將first模組的AndroidManifest改回成作為總app的一個模組時的樣子。
5.2.在專案的gradle.properties中,新增isUniqueApp變數,設定為true。用isUniqueApp來標記功能模組是否作為獨立的app。isUniqueApp = true時,表示功能模組作為獨立的app執行,isUniqueApp = false時,表示功能模組作為總app的一個模組,不能單獨執行。
5.3.在first模組的build.gradle中,將:
apply plugin: 'com.android.application'
改為
if(isUniqueApp.toBoolean()){ apply plugin: 'com.android.application' }else{ apply plugin: 'com.android.library' }
意思是:如果這個模組是作為單獨app執行的,那麼apply plugin: 'com.android.application';
如果這個模組是作為總app的一個模組,那麼apply plugin: 'com.android.library'
5.4.在first模組的build.gradle中,新增:
sourceSets { main{ if(isUniqueApp.toBoolean()){ manifest.srcFile 'src/main/java/debug/AndroidManifest.xml' }else{ manifest.srcFile 'src/main/AndroidManifest.xml' java{ exclude 'debug/**' } } } }
意思是:如果這個模組是作為單獨app執行的,那麼manifest資源使用src/main/java/debug/AndroidManifest.xml;
如果這個模組是作為總app的一個模組,那麼manifest資源使用src/main/AndroidManifest.xml,並且排除debug資料夾中的內容
對second模組的操作和first模組一樣。
5.5.將app模組下引入first、second模組依賴的程式碼改為:
if(!isUniqueApp.toBoolean()){ implementation project(':first') implementation project(':second') }
意思是:如果first模組和second模組是作為單獨app執行的,那麼不引入first、second模組;
如果first模組和second模組是作為總app的模組,那麼引入first、second模組
6.為了標題和圖示的統一,我們為first模組和second模組設定一個應用圖示和應用名稱:
先把app模組中和圖示有關的圖片移動到base模組,以保證每個模組都可以訪問這些資原始檔。然後給application標籤設定label屬性和icon屬性
這樣就完成了專案的元件化。
二、ARouter的基本使用
ARouter是阿里巴巴開源的路由框架,可以使用ARouter方便的進行Activity隱式跳轉。
1.引入ARouter
在專案的ext.libs中,新增:
arouterCompiler : "com.alibaba:arouter-compiler:1.1.4", arouterApi : "com.alibaba:arouter-api:1.3.1"
在base模組,新增:
api libs.arouterApi
在first模組和second模組,新增:(需要跳轉的每個模組都要新增)
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [ moduleName : project.getName() ] } } } } dependencies { ... annotationProcessor libs.arouterCompiler }
2.初始化ARouter
3.實現介面跳轉:
3.1.先在FirstMainActivity中添加了路徑:
@Route(path = "/first/main")
路徑需要至少兩級,第一級是指分組。
3.2.在MainActivity中新增跳轉程式碼:
// 1. 應用內簡單的跳轉(通過URL跳轉在'進階用法'中) ARouter.getInstance().build("/first/main").navigation();
3.3.在gradle.properties中將isUniqueApp設定為false,因為在元件化開發時,各個模組是獨立的,只有非元件化模式才能實現跳轉到不同的模組。
4.如果要跳轉時需要帶引數,程式碼為:
// 2. 跳轉並攜帶引數 ARouter.getInstance().build("/first/main") .withLong("key1", 666L) .withString("key2", "888") .withObject("key3", Your_Data) .navigation();
其中,Your_Data是一個實現了序列化的物件。
執行程式,Log控制檯可以看到:
com.simple.component D/FirstMainActivity: onCreate: 666 com.simple.component D/FirstMainActivity: onCreate: 888
以上,就是ARouter的基本使用。
原始碼已上傳: