Android業務組件化之子模塊SubModule的拆分以及它們之間的路由Router實現

前言:

     前面分析了APP的現狀以及業務組件化的一些探討(Android業務組件化之現狀分析與探討),以及通訊的橋樑Scheme的使用(Android業務組件化之URL Scheme使用),今天重點來聊下子模塊SubModule的拆分以及它們之間的路由Router實現。本篇涉及的相關知識比較多,閱讀本篇之間須要大體瞭解一下Java的註解(Java學習之註解Annotation實現原理)、Java的動態代理機制(Java設計模式之代理模式(Proxy))等。業務組件化是一個按部就班的過程,一開始很難就能拿出終極解決方案,仍是一步步來走的比較踏實實在。
html

   業務組件化相關文章地址:java

咱們首先搞清楚什麼是業務組件?

    搞清楚這個對咱們來講相當重要,不然很難拆分業務與依賴庫,也很難搞清楚哪些類應該放在業務子模塊裏面哪些類應該放在依賴庫裏面。android

 1.)和業務無關

     徹底和業務沒有一點關係,好比項目中經常使用的各類Utils工具類,一些公共自定義控件例如顯示圓角圖片的ImageView等數據庫

 2.)弱業務

    爲何稱之爲弱業務,緣由就是這些不是完整的業務,可是又和APP業務相關,好比咱們的網絡請求,數據庫操做等。設計模式

 3.)業務

   這個就是咱們針對要拆分的業務組件,一個完整的獨立的業務線才能稱之爲業務,好比咱們APP的登陸註冊業務等。網絡

業務組件的拆分粒度?

    業務組件的拆分將是整個整改的重點,關於拆分的粒度也將成爲討論的焦點,究竟是粗一點好仍是細一點好?粗一點更容易拆分,細一點更容易解耦靈活度高,這個根據實際狀況來定,因爲咱們項目整改的過程當中不能影響到新需求的開發,開始仍是以粗一點的粒度進行拆分,先把大體幾個業務拆分出來,後期慢慢再作細。app

子模塊SubModule拆分:

1.)子模塊沒有拆分之間

  頁面跳轉框架

Intent intent = new Intent(this, XXX.class);
startActivity(intent);

 數據傳遞maven

  直接頁面startActivityForResult返回獲取, 間接頁面經過存儲或者變量 ,或者藉助開源框架EventBus等傳遞ide

沒有拆分的這種開發方式,其實使用起來簡單方便,可是這種顯示調用沒有任務文檔,每個跳轉頁面都要和相關開發人員溝通,溝通成本比較高。

2.)拆分子模塊以後

 拆分子模塊以後,任何模塊之間的跳轉都要採用路由Router中轉,須要在相關Activity中配置以下信息

        <activity
            android:name=".GoodsDetailActivity"
            android:theme="@style/AppTheme">
            <intent-filter>
                <data
                    android:host="goods"
                    android:path="/goodsDetail"
                    android:port="8888"
                    android:scheme="xl"/>
                <category android:name="android.intent.category.DEFAULT"/>

                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.BROWSABLE"/>
            </intent-filter>
        </activity>

頁面跳轉

    /**
     * 經過uri跳轉指定頁面
     *
     * @param url
     */
    private void openRouterUri(String url) {
        PackageManager packageManager = mContext.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
        boolean isValid = !activities.isEmpty();
        if (isValid) {
            mContext.startActivity(intent);
        }
    }

數據的傳遞一樣能夠直接頁面startActivityForResult返回獲取, 間接頁面經過存儲或者變量 ,或者藉助開源框架EventBus等傳遞,可是這些弱業務公共數據統一放在依賴庫裏。模塊之間不存在代碼引用。經過這種方式android,iOS與H5客戶端能夠經過一些簡單的url來實現跳轉了,通維護一份文檔來約束各個頁面的參數。

3.)路由Router簡單實現

   1.定義兩個註解參數,一個標示URI註解,一個標示參數

RouterUri.java
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface RouterUri {

    String routerUri() default "";

}
RouterParam.java
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface RouterParam {
    
    String value() default "";
    
}

 2.定義一個URI協議接口

IRouterUri.java
public interface IRouterUri {

    @RouterUri(routerUri = "xl://goods:8888/goodsDetail")//請求Url地址
    void jumpToGoodsDetail(@RouterParam("goodsId") String goodsId, @RouterParam("des") String des);//參數商品Id 商品描述

}

3.定義一個單例,內部經過動態代理機制實現跳轉

public class XLRouter {
    private final static String TAG = XLRouter.class.getSimpleName();
    private static IRouterUri mRouterUri;
    private static Context mContext;


    /**
     * 初始化
     */
    public static void initXLRouter(Context context) {
        mContext = context.getApplicationContext();
        mRouterUri = create(IRouterUri.class);
    }

    /**
     * 返回Api
     */
    public static IRouterUri routerUri() {
        return mRouterUri;
    }

    private static IRouterUri create(Class<?> aClass) {
        return (IRouterUri) Proxy.newProxyInstance(aClass.getClassLoader(), new Class<?>[]{aClass},
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
                        StringBuilder stringBuilder = new StringBuilder();
                        RouterUri reqUrl = method.getAnnotation(RouterUri.class);
                        Log.e(TAG, "IReqApi---reqUrl->" + reqUrl.routerUri());
                        stringBuilder.append(reqUrl.routerUri());
                        //Type[] parameterTypes = method.getGenericParameterTypes();//獲取註解參數類型
                        Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();//拿到參數註解
                        //Annotation[] annotation = method.getDeclaredAnnotations();
                        int pos = 0;
                        for (int i = 0; i < parameterAnnotationsArray.length; i++) {
                            Annotation[] annotations = parameterAnnotationsArray[i];
                            if (annotations != null && annotations.length != 0) {
                                if (pos == 0) {
                                    stringBuilder.append("?");
                                } else {
                                    stringBuilder.append("&");
                                }
                                pos++;
                                RouterParam reqParam = (RouterParam) annotations[0];
                                stringBuilder.append(reqParam.value());
                                stringBuilder.append("=");
                                stringBuilder.append(args[i]);
                                Log.e(TAG, "reqParam---reqParam->" + reqParam.value() + "=" + args[i]);
                            }
                        }
                        //下面就能夠執行相應的跳轉操做
                        openRouterUri(stringBuilder.toString());
                        return null;
                    }
                });
    }

    /**
     * 經過uri跳轉指定頁面
     *
     * @param url
     */
    private static void openRouterUri(String url) {
        PackageManager packageManager = mContext.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
        boolean isValid = !activities.isEmpty();
        if (isValid) {
            mContext.startActivity(intent);
        }
    }
}

4.)在進行XLRouter初始化

XLRouter.initXLRouter(this);

5.調用方式

XLRouter.routerUri().jumpToGoodsDetail("1000110002","goods des");

總結:

   要實現真正的業務組件化任重而道遠,咱們這裏實現第一步拆分子模塊,讓各個模塊的代碼各自維護,先解耦他們之間的依賴關係,在app殼工程經過compile project(':umeng_social_sdk_library')這種方式選擇性接入哪一個子模塊,開發過程當中開發哪一個模塊就引入哪一個模塊,測試環節也是如此,測試哪一個模塊打包引入哪一個模塊,最終測試須要引入所有相關模塊,測試上線。

相關文章
相關標籤/搜索