使用ARouter實現組件化

ARouter是阿里在github上面的一個開源項目,地址是:ARouter 本文不是重點分享ARouter的使用,而是分享使用ARouter如何去組件化。關於它的詳細使用,你們能夠看文檔以及加羣向詢問。關於如何編寫一個路由實現組件化,推薦看我同事的一篇文章手把手教你寫Router框架入門篇java

組件化的優勢android

  1. 解耦,使得各自業務模塊專一於本身的業務實現,而能夠不關係別的模塊業務。git

  2. 方便開發,在多人開發的時候,能夠各自開發本身的特定模塊,除了底層模塊以外github

  3. 可配置,複用性強,針對不一樣的App,能夠有不一樣的模塊而沒必要作出大的改變。網絡

  4. 每一個模塊能夠獨立運行,方便開發調試。數據結構

  5. 你們補充
    組件化開發的實現app

![圖片上傳中...]框架

項目結構是: maven

配置ide

  1. 你們按照ARouter的文檔去配置一些東西,須要注意的是每個模塊都必須引入compile sdk,處理API SDk能夠在Base sdk裏面引入就行。

  2. Annotation sdk不用咱們引入,他會本身自動依賴引入

  3. 在開發的時候,每個module 的分組都必須不一樣,或者將會有一個 類重複的錯誤。分組就是path的第一個"/"與第二個"/"之間。

思路
咱們是須要拆分組件,不一樣的模塊負責本身的業務實現,不和其餘模塊有依賴關係的存在。假如這個模塊須要啓動別的Activity或者是調用別的模塊方法,咱們就經過ARouter提供的方法去實現。
模塊圖以下:

clipboard.png

  1. App模塊 App模塊就是咱們的Apk模塊,他是咱們的最終產物。他能夠按照須要配置本身須要的模塊,進行一些初始化的工做。

  2. module模塊 Module模塊就是咱們的業務實現模塊,他是隻負責本module的業務而不負責其餘的業務,他是經過使用ARouter提供的方法和接口,實現調用外部數據和提供方法給外部調用,也就是圖裏面的Provider。

  3. 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都是能夠獨立運行的,方便開發和調試。那麼,咱們應該怎麼弄?

  1. 咱們提供兩種環境,一個是debug,一種是release,debug的時候,咱們是可運行的獨立模塊,release的時候,咱們是library。

  2. 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添加。 最終結果如圖:

clipboard.png

App獨立運行:
![圖片上傳中...]
App2獨立運行:
clipboard.png
home獨立運行:
clipboard.png

module1獨立運行:

clipboard.png

組件化開發的建議

  1. 在咱們每個模塊文檔以後,咱們應該使用arr的形式引入依賴,上傳咱們的maven庫,再去compile下來,同時註釋掉setting.gradle的配置,這樣子有助於編譯加快。

  2. 刪除各個module的test代碼,也就是src目錄下的test,由於那些都是包含一些task的,在同步或者是編譯的時候會被執行,減慢了編譯速度。

  3. 四大組件應該在各自module裏面聲明。

  4. 在Base中提供一個BaseApplication。

舊項目組件化過程實踐

最近在作公司的App,和同事一塊兒把負責的App組件化了,在這個過程當中有一些坑跟你們分享一下,避免你們再踩。

  1. 不要一步完全的組件化,步子不要邁得太大,建議是先將比較容易的組件進行拆分出來,先作成模塊,而後一邊進行業務的迭代,兩邊都不耽誤,除非你有足夠時間進行組件化工做纔去完全組件化。

  2. 關於資源的拆分,一些style,一些常見的string,一些共用的圖片,drawable等資源,建議存放在base module當中,能夠共用。對於屬於不一樣模塊的資源,建議不要存放在base,可能一開始你直接把全部的資源都放到base裏面會比較好作,好比不用擔憂編譯錯誤,資源沒法尋找到,須要一個一個的複製的問題,可是,你存放到了base,而base模塊,通常開發過程當中,是常常變更的,那麼,就是他會常常被編譯,就會帶來一個編譯的速度問題,因此應該各個模塊存放本身的資源。

  3. 關於Base的依賴庫問題,好比咱們可能有自家的sdk,第三方的依賴等等,這些,與業務邏輯無關的依賴,建議是使用一個單獨的project 進行二次封裝,封裝完成以後,打包arr 依賴,上傳自家maven庫,經過compile 進行base,或者是特定模塊,不建議直接在app中新建module。好比,咱們要引入volley,咱們應該使用一個新的project,對volley進行二次封裝,穩定以後,經過compile arr 引入base 或者是其餘模塊中。這樣子這些與業務邏輯無關的也方便公司其餘項目使用。

  4. 針對舊項目拆分的module,能夠暫時不編寫debug,也就是能夠不用使得舊項目能夠獨立運行,由於他涉及的初始化邏輯可能較多,時間不夠,直接被app依賴運行測試。針對新的module,能夠編寫debug來使得新module獨立運行,方便調試。

組件化帶來的問題

因爲項目的組價化,可能須要每一個業務拆分的比較開,那麼將會致使module也比較的多。到了最後,多是一個模塊帶一個Activity以及一個Fragment做爲一個組件,那麼將會比較難的開發,因此,模塊的拆分,咱們須要按照咱們實際項目進行劃分模塊,不要劃分太細緻。同時,在舊項目組件化過程當中,因爲各個模塊還沒有成熟,尚未穩定,那麼就會有比較多的模塊進行編譯,速度也是比較慢的,因此舊項目的拆分也是須要按照必定的步驟慢慢拆分。同時,建議使用Activity+Fragment的方式進行組件化,方便被別的組件使用,Activity不涉及通常邏輯。有時候修改base庫,須要修改依賴方式會比較的麻煩。有時候會有資源衝突問題,這個咱們在gradle裏面爲模塊資源添加一個前綴解決

相關文章
相關標籤/搜索