路由组件核心原理探究 - 手写一个ARouter

本文深入探讨了路由组件的核心原理,通过手写一个简单的ARouter实现,涵盖了路由信息收集、分组、生成路由表和入口文件、运行时加载路由等关键步骤。在编译时,注解处理器收集并分组路由信息,生成路由表文件和入口文件。运行时,通过扫描dex文件加载路由入口信息到内存,按需加载路由表,实现高效路由跳转。
摘要由CSDN通过智能技术生成

本篇博文基于自己实现的路由组件,主要功能包括Activity路由跳转,支持自定义服务。代码实现比较简单,重在探讨路由组件的核心原理,如需品尝功能更全、代码更屌的框架,可以直接前往ARouter,下载源码,即可。

手写一个ARouter;

一、核心原理

还是那句话,没什么是一张图解决不了的问题,如果有,那就是两张。O(∩_∩)O

路由组件的核心原理,如上图所示:

共分为两大部分:编译时 + 运行时。

a)编译时

1、路由信息收集

路由信息收集的前提是有数据源,而这个数据源就是我们自定义的编译时注解Route。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    //配置路由,格式:/xxx/yyy,必须以/开头
    String path();
}

当然,只是定义一个编译时注解是没用的,需要与之配合的编译时注解处理器来完成相应的处理工作。

使用:

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

我们这个所说的路由信息就是”/main/mainactivity“及相关信息,相关信息是指该路由对应的目标类,比如本例的MainActivity;还有目标类的类型,比如本例的是Activity,这样实现跳转时我们知道下一步的动作是startActivity了;携带的参数等等。

主要原理如下:

Java编译时注解框架会在编译时扫描所有的Java源文件,并将带有指定注解的所有元素Element作为参数,传递给我们的注解处理器的process方法进行相应的处理。

注解处理方法的第一步就是收集路由信息。路由这个词意味着分组,不然如何路由呢?因此,在收集路由信息的同时,我们按照一定的规则进行分组 - 比如/main/mainactivity,则属于main分组,同一分组下的所有路由信息就对应了一张路由表。也就是说有多少个分组,后面我们就会生成多少个路由表文件。示例:

/**
 * AUTO GENERATED, MODIFY IS USELESS @WRITE BY JSON */
public class app_Group_main implements IRouteGroup {
  public void loadRouteInfo(Map<String, RouteMeta> routes) {
    routes.put("/main/mainactivity",RouteMeta.build("/main/mainactivity","main",MainActivity.class,TypeEnum.ACTIVITY));
    routes.put("/main/shopactivity",RouteMeta.build("/main/shopactivity","main",ShopActivity.class,TypeEnum.ACTIVITY));
  }
}

2、路由信息分组、生成路由表文件、路由入口文件

路由信息分组在第一部分已经说了,这里不再说了。

路由信息完成分组之后,下一步的动作就是生成路由表文件,路由表文件包含了同一分组下的所有路由信息,这是一个java文件,文件名可以按照一定的规则来进行命名,比如

app_Group_main,即 module名 + ”_“ + ”Group “+ ”_“ + 分组名。

一个大型的App,路由表文件的数量是非常多的。如果一开始就把所有的路由信息都加载到内存中,这对于本就内存不宽裕的手机设备来说并不是好的做法。比较优秀的做法是只加载用到的路由信息对应的路由表。这就需要借助路由入口文件实现懒加载了。路由入口文件示例如下:

/**
 * AUTO GENERATED, MODIFY IS USELESS @WRITE BY JSON */
public class JRouter_Entry_app implements IEntry {
  public void loadRouteEntry(Map<String, Class<? extends IRouteGroup>> entries) {
    entries.put("test",app_Group_test.class);
    entries.put("main",app_Group_main.class);
  }
}

我们会在生成路由表文件的同时,生成路由入口文件,如上述代码所示。原因已经说过了,不再详述了。

b)运行时

3、运行时扫描dex文件,加载路由入口信息至内存

在初始化路由组件的时候,我们只会把路由入口文件中的所有信息加载到内存中。

4、运行时,根据路由信息,加载路由表至内存中

在进行具体的路由跳转时,我们才会去加载相应的路由表。比如MainActivity,我们首先会查找路由入口信息,根据分组main找到了对应的路由表文件是app_Group_main.class,则利用反射将app_Group_main的所有路由信息加载到内存中。

具体涉及到运行时扫描dex文件,在后面的源码分析中会详述。

小结:

a)路由生成:收集路由信息  ->  对路由信息分组  ->  每个路由分组生成一个路由表文件  ->  生成路由入口文件;

b)路由跳转:

  • [依据分组名]查找路由入口:在路由入口文件查找对应的路由表文件是哪个;
  • 加载路由表文件;
  • 根据路由path信息,在路由表文件中查找具体的路由信息;
  • 拿到足够的信息,进行路由跳转。   

二、手写一个ARouter,探究路由实现核心原理

本部分同样按照博客开始的图示,分四个部分实现。

2.1、路由信息收集 & 分组

a)编译时注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    //配置路由
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值