一種簡單易懂的 Android 項(xiàng)目模塊間解藕方案

在 Android 開發(fā)中,當(dāng)項(xiàng)目增加一定規(guī)模之后,一般都會采用多模塊的項(xiàng)目結(jié)構(gòu)。當(dāng)然也能采用插件化的開發(fā)模式,具體采用什么開發(fā)模式,開發(fā)者可以自行定奪。這里將介紹下我所熟悉的一種模塊化開發(fā)機(jī)制。本質(zhì)是基于 gradle 的 Multi-Project 構(gòu)建和 Java 的動態(tài)代理機(jī)制。

這個方案現(xiàn)已提取開源:https://github.com/stefanJi/Android-MPD

// settings.gradle

include ':app', ':feature_a', ':feature_b', ':feature_c'
image

利用這套機(jī)制時:比如開發(fā)者開發(fā) A 功能時,只會涉及 feature_a 模塊中代碼的修改,那么開發(fā)者就可以讓 gradle 不編譯其他模塊中的代碼(在 settings.gradle 中注釋不需要的模塊),從而能夠減少本地開發(fā)時的編譯耗時,也能夠讓某些代碼只會在開發(fā)期間存在(比如為了方便測試單獨(dú)提供的 admin 模塊)。

選擇性編譯

同時為了避免因?yàn)槟K間彼此依賴,導(dǎo)致個別模塊不編譯的目標(biāo)無法實(shí)現(xiàn)。于是要求各個模塊之間不能直接依賴具體實(shí)現(xiàn),只能依賴某個公共模塊(比如 app 模塊)提供的接口。

image

具體實(shí)現(xiàn)是:

在 app 模塊中定義模塊 feature_a 能夠提供的功能,比如打開 feature_a 中的一個 Activity.

public interface IFeatureA {
    @Nullable
    public Class<Activity> getActivityOfA();
}

然后在 feature_a 中實(shí)現(xiàn)這個接口:

public class FeatureA implements IFeatureA {
    public Class<Activity> getActivityOfA() {
        return FeatureAActivity.class;
    }
}

然后在 app 中注入 IFeatureA 接口的具體實(shí)現(xiàn):

public class FeatureRegister {

    private static IFeatureA featureA;

    @Nullable
    public static IFeatureA getFeatureA() {
        if (featureA == null) {
            try {
                // 這里使用反射能夠在即使 feature_a 模塊未加入編譯之后也能夠成功編譯
                featureA = (IFeatureA) Class.forName("io.github.stefanji.feature_a.FeatureA").newInstance();
            } catch (ClassNotFoundException e) {
                // 如果 feature_a 未加入編譯,則會觸發(fā)異常
            }
        }
        return featureA;
    }
}

然后 feature_b 需要獲取 feature_a 的 FeatureAActivity:

IFeatureA featureA = FeatureRegister.getFeatureA();
Class<Activity> activityClass = null;
if (featureA != null) {
    activityClass = featureA.getActivityOfA();
};

動態(tài)代理未加入編譯的模塊

在上面我們已經(jīng)能夠?qū)崿F(xiàn)不編譯某些模塊,并且項(xiàng)目整體編譯不會出現(xiàn)問題。但是每次訪問其他模塊提供的功能時,從 app 模塊獲取實(shí)現(xiàn)之后需要進(jìn)行判空處理。不是太優(yōu)雅。

于是可以利用動態(tài)代理,如果目標(biāo)模塊沒有被編譯,那么就返回一個實(shí)現(xiàn)了目標(biāo)模塊功能接口的代理對象。
修改 app 中代碼如下:

@NotNull
public static IFeatureA getFeatureA() {
    if (featureA == null) {
        try {
            featureA = (IFeatureA) Class.forName("io.github.stefanji.feature_a.FeatureA").newInstance();
        } catch (ClassNotFoundException e) {
        }
        // 如果 feature_a 模塊未沒編譯,F(xiàn)eatureA 類將找不到,就動態(tài)生成一個 Proxy 類
        if (featureA == null) {
            featureA = (IFeatureA) Proxy.newProxyInstance(FeatureRegister.class.getClassLoader(),
                    new Class[]{IFeatureA.class},
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Class returnType = method.getReturnType();
                            // 讓原始類型返回零值
                            if (returnType == boolean.class) {
                                return false;
                            }
                            if (returnType == int.class) {
                                return 0;
                            }
                            if (returnType == float.class) {
                                return 0f;
                            }
                            //...
                            // 讓引用類型返回 null
                            return null;
                        }
                    });
        }
    }
    return featureA;
}

這樣就不用做如下判空了:

if (featureA != null) {
    activityClass = featureA.getActivityOfA();
};

自動化

每新增一個模塊,我們就需要重復(fù)上面的步驟,在 FeatureRegister 中注冊新的 Feature 接口。這種重復(fù)的操作,當(dāng)然可以利用注解處理器或 gradle transform 之類的代碼生成機(jī)制,讓編譯器去自動生成模板代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、模塊化淺談 1. Android 模塊化開發(fā)介紹; 模塊化開發(fā)思路就是:單獨(dú)開發(fā)每個模塊,用集成的方式把他們組...
    路Promenade閱讀 28,006評論 31 136
  • 文章大綱 一、項(xiàng)目模塊化初步介紹二、項(xiàng)目模塊化的兩種模式與比較三、大型項(xiàng)目模塊化的演進(jìn)四、項(xiàng)目模塊化總結(jié)五、參考文...
    故事愛人c閱讀 804評論 0 5
  • 在App開發(fā)的初期,代碼量不大,業(yè)務(wù)量比較少,一個App作為一個單獨(dú)的模塊進(jìn)行開發(fā),往往問題不大。但隨著業(yè)務(wù)的增多...
    AC編程閱讀 5,093評論 3 30
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,822評論 28 54
  • 信任包括信任自己和信任他人 很多時候,很多事情,失敗、遺憾、錯過,源于不自信,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,361評論 4 8

友情鏈接更多精彩內(nèi)容