android Route模块化路由设计方案

背景:

我们在移动端开发过程,随着业务越来越多,越来越复杂,在架构中会将业务进行剥离和抽取,这样会出现许多业务模块。但是各业务模块又有业务关联,常见的就是Activity之间的跳转。但是,一些大的公司,或者业务线非常多的app大多数采用混合模式,

常见的就是H5和app混合,特别是电商商业比较常见。这时候H5通过连接跳转到原生,我们只需要知道原生页面的keyCode,就能和原生一样去访问原生业务。

问题:

在Activity之间跳转,我们可以用Intent现有的显示和隐式跳转,如果在相同模块类跳转很方便,在不同模块中就要需要知道目标Activity的className,如果别人改变类型或者类的文件路径,就会导致其他模块无法访问到。

如果我们把Activity和对应的key进行绑定,通过绑定来跳转。这样就非常方便。

解决方案:

"路由",路由相当于Activity的门牌号引导系统,我只要知道门牌号,即使是瞎子,也能找到家,所以我们只要给Activity定义好唯一的routeCode,就能找到对应的页面。

路由的设计:

1.注解

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

网上很多关于 Java Annotation 的文章,看得人眼花缭乱。Java Annotation 本来很简单的,结果说的人没说清楚;弄的看的人更加迷糊。

我按照自己的思路,对 Annotation 进行了整理。理解 Annotation 的关键,是理解 Annotation 的语法和用法,对这些内容,我都进行了详细说明;理解 Annotation 的语法和用法之后,再看 Annotation 的框架图,可能有更深刻体会。废话就说这么多,下面开始对 Annotation 进行说明。若您发现文章中存在错误或不足的地方,希望您能指出!

1.1、Annotation 架构

1.2. ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型

public enum ElementType {
    TYPE,               /* 类、接口(包括注释类型)或枚举声明  */

    FIELD,              /* 字段声明(包括枚举常量)  */

    METHOD,             /* 方法声明  */

    PARAMETER,          /* 参数声明  */

    CONSTRUCTOR,        /* 构造方法声明  */

    LOCAL_VARIABLE,     /* 局部变量声明  */

    ANNOTATION_TYPE,    /* 注释类型声明  */

    PACKAGE             /* 包声明  */
}

1.3. RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同

"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联。

  • a) 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。
  • b) 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
  • c) 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。

2.路由设计

Route

@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Route {
    String routeCode() default "";
}

Route注解:定义了作用于类上的,且申明了一个routeKey变量;

小试牛刀:

1.创建一个Activity并使用注解绑定一个routeKey:

@Route(routeCode = "1001")
public class RoueActivity1 extends Activity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

2.创建一个路由管理工具:RouteManager

2.1获取当前包下,直接注解Route所关联的Activity,证明这些类都支持路由,并存储起来(一般这个方法在application中初始化)

public void initAppPackRouteActivity() {
    PackageManager manager = mContext.getPackageManager();
    try {
        PackageInfo packageInfo = manager.getPackageInfo(
                mContext.getPackageName(), PackageManager.GET_ACTIVITIES);

        if (packageInfo != null) {
            for (ActivityInfo info : packageInfo.activities) {
                String className = info.name;
                Class<?> cls = Class.forName(className);
                Route route = cls.getAnnotation(Route.class);
                if (route != null && !TextUtils.isEmpty(route.className())) {
                    RouteActivityBean bean = new RouteActivityBean(route.routeCode(), route.className());
                    routeActivityBeans.add(bean);
                   
                }


            }
        }

    } catch (Exception e) {

    }
}

2.2 路由的使用

     1.路由的使用(原生之间的跳转)

public void routeDetail(String code, Bundle bundle) {

    for (RouteActivityBean bean : routeActivityBeans) {
        if (TextUtils.equals(code, bean.getRouteCode())) {
          //找到路由key,进行跳转
            Intent intent = new Intent();
            intent.setClassName(mContext.getPackageName(), bean.getActivityName());
            intent.putExtras(bundle);
            mContext.startActivity(intent);
            break;
        }
    }

}

 2.H5访问原生页面

public void routeDetail(String routeUrl) {
   //routeCode是html中routeKye的key
    if (routeUrl.contains(routeCode) && routeUrl.contains("?")) {

        String[] text = routeUrl.split("\\?");
        String[] keyValue = text[1].split("&");
        Bundle bundle = new Bundle();
        String routeCode = "";//获取路由编号
        for (String value : keyValue) {
            if (TextUtils.isEmpty(value)) {
                continue;
            }
            String[] kv = value.split("=");
            String key = "";
            String keyByValue = "";
            if (kv.length == 1) {
                key = kv[0];

            } else if (kv.length == 2) {
                key = kv[0];
                keyByValue = kv[1];
            }
            if (TextUtils.isEmpty(key)) {
                continue;
            }
            if (TextUtils.equals(routeCode, key)) {
                //key
                routeCode = keyByValue;
            } else {
                bundle.putString(key, keyByValue);
            }


        }
        routeDetail(routeCode, bundle);//转换成原生,访问原生页面

    } else {
        //默认走内置h5,的页面,自己配置,如果没有路由标识,业务自行处理

    }


}

3.如何使用。

 3.1原生:

Bundle bundle=new Bundle();

bundle.putString("name","nihao");

  routeDetail("1001",bundle);

3.2 H5使用:

先定义一个路由关键字:routeCode;

public static String h5="www.123.com?routeCode=1001&name=nihao";

routeDetail(h5);

如果定义的1001路由存在,就会找到对应的页面,跳转过去,在原生页面正常解析即可。

依赖库:implementation 'com.github.it90msart:LBRoute:1.0.0'

github项目地址:https://github.com/it90msart/LBRoute

总结:路由设计并不繁琐,但是在开发过程中使用好,可以很好的解耦,提升效率,提升组件化开发。也便于module业务间的维护。

代码GIT地址:

https://github.com/it90msart/LBRoutehttps://github.com/it90msart/LBRoute

集成依赖库: 依赖库implementation 'com.github.it90msart:LBRoute:1.0.0'

猜你喜欢

转载自blog.csdn.net/qq36246172/article/details/114140434