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')这种方式选择性接入哪一个子模块,开发过程当中开发哪一个模块就引入哪一个模块,测试环节也是如此,测试哪一个模块打包引入哪一个模块,最终测试须要引入所有相关模块,测试上线。

相关文章
相关标签/搜索