背景:
我们在移动端开发过程,随着业务越来越多,越来越复杂,在架构中会将业务进行剥离和抽取,这样会出现许多业务模块。但是各业务模块又有业务关联,常见的就是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