Skip to content

通过Route注解去探究如何实现路由跳转

Xia Shengming edited this page Feb 17, 2019 · 2 revisions

上节大概了解了根据路由地址去实现跳转的方式,只是做个启发,这节我们就详细介绍一下实现的细节。

通过Route注解去探究如何实现路由跳转

简单讲,要通过Route注解生成我们的路由表,首先第一步需要定义注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    /**
     * 路由的路径
     * @return
     */
    String path();

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

}

这里看到Route注解里有path和group,这便是仿照ARouter对路由进行分组。因为当项目变得越来越大庞大的时候,为了便于管理和减小首次加载路由表过于耗时的问题,我们对所有的路由进行分组。在ARouter中会要求路由地址至少需要两级,如"/xx/xx",一个模块下可以有多个分组。这里我们就将路由地址定为必须大于等于两级,其中第一级是group。如app module下的路由注解:

@Route(path = "/main/main")
public class MainActivity extends AppCompatActivity {}

@Route(path = "/main/main2")
public class Main2Activity extends AppCompatActivity {}

@Route(path = "/show/info")
public class ShowActivity extends AppCompatActivity {}

在项目编译的时候,我们将会通过apt生成EaseRouter_Root_app文件和EaseRouter_Group_main、EEaseRouter_Group_show等文件,EaseRouter_Root_app文件对应于app module,里面记录着本module下所有的分组信息,EaseRouter_Group_main、EaseRouter_Group_show文件分别记载着app module下每个分组的所有路由地址和ActivityClass映射信息。
本demo在编译的时候会生成类如下所示,先不要管这些类是怎么生成的,仔细看类的内容

public class EaseRouter_Root_app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("main", EaseRouter_Group_main.class);
    routes.put("show", EaseRouter_Group_show.class);
  }
}


public class EaseRouter_Group_main implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/main/main",RouteMeta.build(RouteMeta.Type.ACTIVITY,Main2\Activity.class,"/main/main","main"));
    atlas.put("/main/main2",RouteMeta.build(RouteMeta.Type.ACTIVITY,Main2\Activity.class,"/main/main2","main"));
  }
}

public class EaseRouter_Group_show implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/show/info",RouteMeta.build(RouteMeta.Type.ACTIVITY,ShowActivity.class,"/show/info","show"));
  }
}

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

public void test() {
    EaseRouter_Root_app rootApp = new EaseRouter_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/main");
        Class<?> mainActivityClass = main.getDestination();

        Intent intent = new Intent(this, mainActivityClass);
        startActivity(intent);
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

}

可以看到,只要有了这些实现了IRouteRoot和IRouteGroup的类文件,我们便能轻易的启动其他module的Activity了。其实这就是路由跳转的原理,这些类文件,我们可以约定好之后,在代码的编写过程中自己手动实现,也可以通过apt生成。作为一个框架,当然是自动解析Route注解然后生成这些类文件更好了。要想自动生成这些路由地址与Activity的映射关系,那么便要了解apt和javapoet了。