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

eiot8028 8年前發布 | 8K 次閱讀 安卓開發 Android開發 移動開發

前言:

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

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

搞清楚這個對我們來說至關重要,否則很難拆分業務與依賴庫,也很難搞清楚哪些類應該放在業務子模塊里面哪些類應該放在依賴庫里面。

1.)和業務無關

完全和業務沒有一點關系,比如項目中常用的各種Utils工具類,一些公共自定義控件例如顯示圓角圖片的ImageView等

2.)弱業務

為什么稱之為弱業務,原因就是這些不是完整的業務,但是又和APP業務相關,比如我們的網絡請求,數據庫操作等。

3.)業務

這個就是我們針對要拆分的業務組件,一個完整的獨立的業務線才能稱之為業務,比如我們APP的登錄注冊業務等。

業務組件的拆分粒度?

業務組件的拆分將是整個整改的重點,關于拆分的粒度也將成為討論的焦點,到底是粗一點好還是細一點好?粗一點更容易拆分,細一點更容易解耦靈活度高,這個根據實際情況來定,由于我們項目整改的過程中不能影響到新需求的開發,開始還是以粗一點的粒度進行拆分,先把大致幾個業務拆分出來,后期慢慢再做細。

子模塊SubModule拆分:

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

頁面跳轉

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

數據傳遞

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

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

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>

</code></pre>

頁面跳轉

    /**

 * 通過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);
    }
}

</code></pre>

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

3.)路由Router簡單實現

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

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

String routerUri() default "";

} </code></pre>

RouterParam.java
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface RouterParam {

String value() default "";

} </code></pre>

2.定義一個URI協議接口

IRouterUri.java
public interface IRouterUri {

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

} </code></pre>

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

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

/**
 * 獲取單例引用
 *
 * @return 單例
 */
public static XLRouter getInstance(Context context) {
    XLRouter inst = mInstance;
    if (inst == null) {
        synchronized (XLRouter.class) {
            inst = mInstance;
            if (inst == null) {
                inst = new XLRouter(context.getApplicationContext());
                mInstance = inst;
            }
        }
    }
    return inst;
}

/**
 * 構造函數
 *
 * @param mContext application
 */
private XLRouter(Context mContext) {
    this.mContext = mContext;
    mRouterUri = create(IRouterUri.class);
}

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

public 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 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);
    }
}

} </code></pre>

4.調用方式

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

總結:

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

 

來自:http://www.cnblogs.com/whoislcj/p/5860138.html

 

 本文由用戶 eiot8028 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!