ARouter是阿里在github上面的一個開源項目,地址是:ARouter 本文不是重點分享ARouter的使用,而是分享使用ARouter如何去組件化。關於它的詳細使用,你們能夠看文檔以及加羣向詢問。關於如何編寫一個路由實現組件化,推薦看我同事的一篇文章手把手教你寫Router框架入門篇java
組件化的優勢android
解耦,使得各自業務模塊專一於本身的業務實現,而能夠不關係別的模塊業務。git
方便開發,在多人開發的時候,能夠各自開發本身的特定模塊,除了底層模塊以外github
可配置,複用性強,針對不一樣的App,能夠有不一樣的模塊而沒必要作出大的改變。網絡
每一個模塊能夠獨立運行,方便開發調試。數據結構
你們補充
組件化開發的實現app
![圖片上傳中...]框架
項目結構是: maven
配置ide
你們按照ARouter的文檔去配置一些東西,須要注意的是每個模塊都必須引入compile sdk,處理API SDk能夠在Base sdk裏面引入就行。
Annotation sdk不用咱們引入,他會本身自動依賴引入
在開發的時候,每個module 的分組都必須不一樣,或者將會有一個 類重複的錯誤。分組就是path的第一個"/"與第二個"/"之間。
思路
咱們是須要拆分組件,不一樣的模塊負責本身的業務實現,不和其餘模塊有依賴關係的存在。假如這個模塊須要啓動別的Activity或者是調用別的模塊方法,咱們就經過ARouter提供的方法去實現。
模塊圖以下:
App模塊 App模塊就是咱們的Apk模塊,他是咱們的最終產物。他能夠按照須要配置本身須要的模塊,進行一些初始化的工做。
module模塊 Module模塊就是咱們的業務實現模塊,他是隻負責本module的業務而不負責其餘的業務,他是經過使用ARouter提供的方法和接口,實現調用外部數據和提供方法給外部調用,也就是圖裏面的Provider。
base模塊 關於base模塊,你們也能夠繼續拆分一些細的模塊,好比把router獨立處理,可是不建議拆分太多,由於base模塊是會變更較大,就是在版本的迭代過程當中,不斷變化的,被拆分較多的話開發起來不是很方便。由於有依賴的傳遞的關係,好比base 依賴於本project的較多模塊,當設計到底層較多模塊修改,那麼就須要一層一層的在傳遞上去。 base模塊應該是與業務無關的模塊,在本例子中,base模塊負責管理Router,同時提供一些基礎的東西,好比BaseActivit,Util資源等。假如咱們有自家的sdk,網絡庫依賴等,建議是在base中引入。
實踐
管理Router
咱們使用一個ModuleManager,提供一個Map,Map是使用對應module的Provider的path做爲key和value。以及相關的數據結構,用來對ARouter的進行二次封裝和管理模塊。 大概實現以下:
public class ModuleManager { private ModuleOptions options; private ModuleManager() { } private static class ModuleManagerHolder { private static final ModuleManager instance = new ModuleManager(); } public static ModuleManager getInstance() { return ModuleManagerHolder.instance; } public void init(ModuleOptions options) { if (this.options == null && options != null) { this.options = options; } } public ModuleOptions getOptions() { return options; } public boolean hasModule(String key) { return options.hasModule(key); } }
ModuleOptions就是具體管理那些包含那些模塊的配置。該類是在App或者是測試module獨立運行(後面提到)的時候進行初始化。例如:
public class CustomApplication extends BaseApplication { @Override public void onCreate() { super.onCreate(); initARouter(); } private void initARouter() { if (LG.isDebug) { ARouter.openLog(); ARouter.openDebug(); ARouter.printStackTrace(); } ARouter.init(this); ModuleOptions.ModuleBuilder builder = new ModuleOptions.ModuleBuilder(this) .addModule(IHomeProvider.HOME_MAIN_SERVICE, IHomeProvider.HOME_MAIN_SERVICE) .addModule(IModule1Provider.MODULE1_MAIN_SERVICE, IModule1Provider.MODULE1_MAIN_SERVICE) .addModule(IModule2Provider.MODULE2_MAIN_SERVICE, IModule2Provider.MODULE2_MAIN_SERVICE) .addModule(IModule4Provider.MODULE4_MAIN_SERVICE, IModule4Provider.MODULE4_MAIN_SERVICE) .addModule(IModule5Provider.MODULE5_MAIN_SERVICE, IModule5Provider.MODULE5_MAIN_SERVICE); ModuleManager.getInstance().init(builder.build()); } }
這樣子就完成了對改App或者是module的管理。
管理服務
咱們使用一個ServiceManager,用來獲取不一樣模塊的服務,即Provider。安裝ARouter的文檔,咱們經過繼承IProvider,編寫一個對應模塊的接口,提供接口方法,在對應模塊實現該Provider。而後該Provider咱們就是在ServiceManager裏面進行管理和獲取。好比: home模塊實現一個IHomeProvider,實現類是HomeProvider。
//接口 public interface IHomeProvider extends IBaseProvider { //Service String HOME_MAIN_SERVICE = "/home/main/service"; //開屏 String HOME_ACT_SPLASH = "/home/act/splash"; //home主頁 String HOME_ACT_HOME = "/home/act/home"; String HOME_TABTYPE = "home_tab_type"; void toast(String msg); void selectedTab(Activity activity,int position); } //實現類 @Route(path = IHomeProvider.HOME_MAIN_SERVICE) public class HomeProvider implements IHomeProvider { private Context context; @Override public void init(Context context) { this.context = context; } @Override public void toast(String msg) { Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } @Override public void selectedTab(Activity activity,int position) { if (activity instanceof HomeActivity) { ((HomeActivity) activity).selectedTab(position); } } }
而後在ServiceManager中,
//也可使用自動注入,這裏是手動發現而且調用 public IModule1Provider getModule1Provider() { return module1Provider != null ? module1Provider : (module1Provider = ((IModule1Provider) MyRouter.newInstance(IModule1Provider.MODULE1_MAIN_SERVICE).navigation())); }
咱們對本Project的全部服務進行管理。而後,在base當中,提供不一樣的Service,對Provider進行調用,同時提供Intent方法,去啓動不一樣模塊的Activity,好比:
//管理調用Provider的某一個特定模塊的Service public class HomeService { private static boolean hasModule() { return ModuleManager.getInstance().hasModule(IHomeProvider.HOME_MAIN_SERVICE); } public static void selectedTab(Activity activity, int position) { if (!hasModule()) return; ServiceManager.getInstance().getHomeProvider().selectedTab(activity, position); } } //管理該module的Activity跳轉 public class HomeIntent { private static boolean hasModule() { return ModuleManager.getInstance().hasModule(IHomeProvider.HOME_MAIN_SERVICE); } public static void launchHome(int tabType) { //HomeActivity MyBundle bundle = new MyBundle(); bundle.put(IHomeProvider.HOME_TABTYPE, tabType); MyRouter.newInstance(IHomeProvider.HOME_ACT_HOME) .withBundle(bundle) .navigation(); } }
Module可獨立運行配置
通過這兩個,咱們就已經基本完成了項目組件化。可是對於組件化,咱們還有一個特色,就是每個module都是能夠獨立運行的,方便開發和調試。那麼,咱們應該怎麼弄?
咱們提供兩種環境,一個是debug,一種是release,debug的時候,咱們是可運行的獨立模塊,release的時候,咱們是library。
debug的時候,咱們須要提供一些測試代碼和一套初始化。 例如:咱們須要module1是能夠獨立運行的,在本demo中,他是一個Fragment做爲主入口被別的模塊添加使用,因此咱們的debug中須要添加一個Activity,一套清單,一些資源。 咱們使用config.gradle去管理咱們的一些外部依賴arr以及咱們的一些編譯版本號,sdk版本號等,以下:
ext {
//...版本號以及arr管理 //home是不是做爲模塊,true的時候是,false的時候能夠獨立運行,ps名字有點不對,不想改了ORZ isMouleDebugHome = true; //module1是不是做爲模塊,true的時候是,false的時候能夠獨立運行 isModule1Debug = true;
}
而後,在跟build.gradle第一行中apply 進去。
apply from: "config.gradle"
而後,使用sourceSets對代碼進行管理,配置debug和release的代碼,module1的結構以下
![圖片上傳中...]
他的gradle配置以下:
if (rootProject.ext.isModule1Debug) { apply plugin: 'com.android.library' } else { apply plugin: 'com.android.application' } android { compileSdkVersion rootProject.ext.android.compileSdkVersion buildToolsVersion rootProject.ext.android.buildToolsVersion defaultConfig { minSdkVersion rootProject.ext.android.minSdkVersion targetSdkVersion rootProject.ext.android.targetSdkVersion versionCode 101 versionName "1.0.1" if (!rootProject.ext.isModule1Debug) { applicationId "com.github.io.liweijie.lib1" } javaCompileOptions { annotationProcessorOptions { arguments = [moduleName: project.getName()] } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { if (!rootProject.ext.isModule1Debug) { manifest.srcFile 'src/debug/AndroidManifest.xml' java.srcDir 'src/debug/java/' res.srcDirs=['src/debug/res'] } else { manifest.srcFile 'src/release/AndroidManifest.xml' java.srcDir 'src/release/java/' } } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile project(':base') testCompile 'junit:junit:4.12' annotationProcessor rootProject.ext.dependencies["aroutercompiler"] }
這裏須要注意的問題是,debug和relase的清單都須要聲明須要的activity以及其餘組件。debug中還應該配置Application,進行ARouter的初始化。 通過這樣子,咱們的每個module都是能夠獨立運行的模塊了。通常而言,release實際上是沒有什麼東西的,由於release須要的就是咱們module自己須要的業務邏輯實現代碼,他是做爲library去使用的,看本身項目是否須要配置relase。 在本項目中,修改對應的config.gradle中的值就可使得module1和home獨立運行或者是做爲lib添加。 最終結果如圖:
App獨立運行:
![圖片上傳中...]
App2獨立運行:
home獨立運行:
module1獨立運行:
組件化開發的建議
在咱們每個模塊文檔以後,咱們應該使用arr的形式引入依賴,上傳咱們的maven庫,再去compile下來,同時註釋掉setting.gradle的配置,這樣子有助於編譯加快。
刪除各個module的test代碼,也就是src目錄下的test,由於那些都是包含一些task的,在同步或者是編譯的時候會被執行,減慢了編譯速度。
四大組件應該在各自module裏面聲明。
在Base中提供一個BaseApplication。
舊項目組件化過程實踐
最近在作公司的App,和同事一塊兒把負責的App組件化了,在這個過程當中有一些坑跟你們分享一下,避免你們再踩。
不要一步完全的組件化,步子不要邁得太大,建議是先將比較容易的組件進行拆分出來,先作成模塊,而後一邊進行業務的迭代,兩邊都不耽誤,除非你有足夠時間進行組件化工做纔去完全組件化。
關於資源的拆分,一些style,一些常見的string,一些共用的圖片,drawable等資源,建議存放在base module當中,能夠共用。對於屬於不一樣模塊的資源,建議不要存放在base,可能一開始你直接把全部的資源都放到base裏面會比較好作,好比不用擔憂編譯錯誤,資源沒法尋找到,須要一個一個的複製的問題,可是,你存放到了base,而base模塊,通常開發過程當中,是常常變更的,那麼,就是他會常常被編譯,就會帶來一個編譯的速度問題,因此應該各個模塊存放本身的資源。
關於Base的依賴庫問題,好比咱們可能有自家的sdk,第三方的依賴等等,這些,與業務邏輯無關的依賴,建議是使用一個單獨的project 進行二次封裝,封裝完成以後,打包arr 依賴,上傳自家maven庫,經過compile 進行base,或者是特定模塊,不建議直接在app中新建module。好比,咱們要引入volley,咱們應該使用一個新的project,對volley進行二次封裝,穩定以後,經過compile arr 引入base 或者是其餘模塊中。這樣子這些與業務邏輯無關的也方便公司其餘項目使用。
針對舊項目拆分的module,能夠暫時不編寫debug,也就是能夠不用使得舊項目能夠獨立運行,由於他涉及的初始化邏輯可能較多,時間不夠,直接被app依賴運行測試。針對新的module,能夠編寫debug來使得新module獨立運行,方便調試。
組件化帶來的問題
因爲項目的組價化,可能須要每一個業務拆分的比較開,那麼將會致使module也比較的多。到了最後,多是一個模塊帶一個Activity以及一個Fragment做爲一個組件,那麼將會比較難的開發,因此,模塊的拆分,咱們須要按照咱們實際項目進行劃分模塊,不要劃分太細緻。同時,在舊項目組件化過程當中,因爲各個模塊還沒有成熟,尚未穩定,那麼就會有比較多的模塊進行編譯,速度也是比較慢的,因此舊項目的拆分也是須要按照必定的步驟慢慢拆分。同時,建議使用Activity+Fragment的方式進行組件化,方便被別的組件使用,Activity不涉及通常邏輯。有時候修改base庫,須要修改依賴方式會比較的麻煩。有時候會有資源衝突問題,這個咱們在gradle裏面爲模塊資源添加一個前綴解決