Android 通过Router注解实现路由跳转

01.首先看ARouter注解实现方案

  • 如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    //首先通过注解添加下面代码
    @Router(path = "/test/TestActivity")
    public class TestActivity extends BaseActivity {

    }

    //跳转
    ARouter.getsInstance().build("/test/TestActivity").navigation();

02.自定义Router注解

  • 模仿ARouter案例,如下所示

    • 这里看到Router注解里有path和group,这便是仿照ARouter对路由进行分组。因为当项目变得越来越大庞大的时候,为了便于管理和减小首次加载路由表过于耗时的问题,我们对所有的路由进行分组。在ARouter中会要求路由地址至少需要两级,如”/xx/xx”,一个模块下可以有多个分组。这里就将路由地址定为必须大于等于两级,其中第一级是group。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //@Retention用来修饰这是一个什么类型的注解。这里表示该注解是一个编译时注解。
    @Retention(RetentionPolicy.CLASS)
    //@Target用来表示这个注解可以使用在哪些地方。比如:类、方法、属性、接口等等。
    //这里ElementType.TYPE 表示这个注解可以用来修饰:Class, interface or enum declaration。
    @Target(ElementType.TYPE)
    public @interface Router {

    /**
    * 路由的路径
    * @return 字符串
    */
    String path();

    /**
    * 将路由节点进行分组,可以实现动态加载
    * @return 字符串,默认值是 ""
    */
    String group() default "";

    }
  • 思考一下,这里为何将地址设置为两级而不是一级呢?

03.查看生成的注解代码

  • 在项目编译的时候,我们将会通过apt生成ARouter_Root_app文件和ARouter_Group_main等文件,EaseRouter_Root_app文件对应于app module,里面记录着本module下所有的分组信息,EaseRouter_Group_main文件分别记载着app module下每个分组的所有路由地址和ActivityClass映射信息。

  • 本demo案例在编译的时候会生成类如下所示,先不要管这些类是怎么生成的,仔细看类的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class ARouter_Root_app implements IRouteRoot {
    @Override
    public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("main", ARouter_Group_main.class);
    }
    }

    public class ARouter_Group_main implements IRouteGroup {
    @Override
    public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/main/FiveActivity",RouteMeta.build(RouteMeta.Type.ACTIVITY,FiveActivity.class,"/main/FiveActivity","main"));
    atlas.put("/main/SixActivity",RouteMeta.build(RouteMeta.Type.ACTIVITY,SixActivity.class,"/main/SixActivity","main"));
    }
    }
  • 分析上面代码原理

    • 看到生成的类分别实现了IRouteRoot和IRouteGroup接口,并且实现了loadInto()方法,而loadInto方法通过传入一个特定类型的map就能把分组信息放入map里。这两个接口是干嘛的我们先搁置,继续往下看
    • 如果我们在main_module中想启动app_module中的MainActivity类,首先,我们已知MainActivity类的路由地址是”/main/FiveActivity”,第一个”/main”代表分组名,那么我们岂不是可以像下面这样调用去得到MainActivity类文件,然后startActivity。这里的RouteMeta只是存有Activity class文件的封装类,先不用理会。
  • 实现跳转简单代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /**
    * 注解生成的代码,在build/generated/source/apt/debug/
    * 模拟跳转到FiveActivity页面
    */
    public void test() {
    ARouter_Root_app rootApp = new ARouter_Root_app();
    HashMap<String, Class<? extends IRouteGroup>> rootMap = new HashMap<>();
    rootApp.loadInto(rootMap);
    //得到/main分组
    Class<? extends IRouteGroup> aClass = rootMap.get("main");
    try {
    HashMap<String, RouteMeta> groupMap = new HashMap<>();
    aClass.newInstance().loadInto(groupMap);
    //得到MainActivity
    RouteMeta main = groupMap.get("/main/FiveActivity");
    Class<?> clazz = main.getDestination();
    Intent intent = new Intent(this, clazz);
    startActivity(intent);
    } catch (InstantiationException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    }
  • 只要有了这些实现了IRouteRoot和IRouteGroup的类文件,我们便能轻易的启动其他module的Activity了。其实这就是路由跳转的原理,这些类文件,我们可以约定好之后,在代码的编写过程中自己手动实现,也可以通过apt生成。作为一个框架,当然是自动解析Route注解然后生成这些类文件更好了。要想自动生成这些路由地址与Activity的映射关系,那么便要了解apt和javapoet了。