Android组件化实战六:路由架构设计

前言

结合前面的模块之间的交互,主要分析了类加载、全局Map记录(跳转目标Class)两种交互方式,以及APT和JavaPoet技术生成类文件,本文分析组件化的路由架构,我们到底需要通过APT和JavaPoet生成什么样的类文件呢?

组件化路由架构设计

Android组件化实战六:路由架构设计_第1张图片

先来看这样一幅架构设计图,组文件记录是一对一的即一个子模块对应一个组文件记录,而一个组文件记录对应多个路径文件记录,第二点比较好理解,因为各个子模块有多个Activity,对应多个路径信息。对应第一点,为什么要生成一对一的组(名)文件记录呢?试想一下,如果用户进入首页,没有进行后续操作,退出应用。而我们还像之前分析的,在application中将全部的activity对应的路径信息记录到Map集合,加载到内存,这显然是不合理的,出于性能优化(内存优化)的考虑,只有用到对应组(模块)时,才去保存对应模块下Activity的路径信息。所以才会根据组(模块)名,生成对应的文件记录。要通过APT和JavaPoet生成哪些类文件呢?

RouterBean对象

在前面的文章中通过全局Map记录方案实现子模块交互时,有涉及到PathBean对象,主要包含目标Activity的路径path,和Class属性。获取class属性,即可实现交互(跳转)。而RouterBean对象就是在PathBean的基础上进行了扩展:

public class RouterBean {

    // 枚举,现在只是处理作用在Activity上的注解
    // 后续还会扩展处理接口上的注解
    public enum Type{
        ACTIVITY
    }

    //枚举类型
    private Type type;
    //类节点
    private Element element;
    //路由的组名
    private String group;
    //路由的地址
    private String path;
    //被@ARouter注解的类对象
    private Class<?> clazz;


    private RouterBean(Builder builder) {
        this.type = builder.type;
        this.element = builder.element;
        this.clazz = builder.clazz;
        this.path = builder.path;
        this.group = builder.group;
    }
    ...
}

Element类节点为什么也要存起来?

  • 因为将来我们要在注解处理器中,循环拿到每个类节点,方便赋值和调用
  • Element它是javax.lang包下的,不属于Android Library

ARouterLoadGroup接口

/**
 * 路由组group对外提供加载数据接口
 */
public interface ARouterLoadGroup {

    /**
     * 加载路由组group数据
     * 比如:"app", ARouter$$Path$$app.class(实现了ARouterLoadPath接口)
     * @return key: "app"即组名, value: "app"分组对应的路由详细对象类
     */
    Map<String, Class<? extends ARouterLoadPath>> loadGroup();
}

Map>

  • 需要生成路由路径文件后,才能生成路由组文件
  • 接口方式容易拓展、通用

ARouterLoadPath接口

/**
 * 路由组group对应的详细path加载数据接口
 * 比如:app分组对应有哪些类需要加载
 */
public interface ARouterLoadPath{
    /**
     * 加载路由组group中的path详细数据
     * 比如:app分组下有这些信息
     * @return key: "app/MainActivity", value:MainActivity信息封装到RouterBean对象中
     */
    Map<String, RouterBean> loadPath();
}

Map

  • OOP思想,让单纯的targetClass变成更灵活的RouterBean对象
  • 接口方式容易拓展、通用

路由框架部署步骤

  • 配置arouter_api/build.gradle
  • 配置common(公共基础库)/build.gradle
  • 完成模拟APT生成的类代码
  • app子模块中,模拟跳转代码
  • 演示跳转

相关的配置问题可以参考前面的文章和文末代码链接查看。这里重点介绍模拟生成的类文件中的逻辑,以及跳转逻辑。在app模块中新建一个目录test,存放模拟apt生成的文件,就是自己手动创建的,主要是为了对流程进行说明,后续会通过apt来生成文件。不同模块对应文件中的逻辑是一样的

Android组件化实战六:路由架构设计_第2张图片

在这里插入图片描述

/**
 * 模拟ARouter路由器的组文件
 */
public class ARouter$$Group$$order implements ARouterLoadGroup {
    @Override
    public Map<String, Class<? extends ARouterLoadPath>> loadGroup() {
        // key: 组名,value: 分组对应的路由详细对象类
        Map<String, Class<? extends ARouterLoadPath>> groupMap = new HashMap<>();
        groupMap.put("order", ARouter$$Path$$order.class);
        return groupMap;
    }
}

返回的是map集合,key表示组名比如order,value表示分组(即模块)对应路由详细对象类

/**
 * 模拟ARouter路由器的组文件对应的路径
 */
public class ARouter$$Path$$order implements ARouterLoadPath {

    @Override
    public Map<String, RouterBean> loadPath() {
        Map<String, RouterBean> pathMap = new HashMap<>();
        pathMap.put("/order/Order_MainActivity",
                RouterBean.create(RouterBean.Type.ACTIVITY, Order_MainActivity.class,
                        "/order/Order_MainActivity", "order"));
        return pathMap;
    }
}

返回的是map集合,key表示路径信息,value表示将目标Activity的信息封装到RouterBean对象,可以从中获取对应的class对象。如果这部分不是很理解,看了跳转逻辑,应该就比较清晰了。

在app的MainActivity中,跳转逻辑如下:

public void jumpOrder(View view) {
    /*Intent intent = new Intent(this, OrderActivity.class);
    intent.putExtra("name", "xpf");
    startActivity(intent);*/

    // 模拟APT生成的类文件,实现跳转
    ARouterLoadGroup loadGroup = new ARouter$$Group$$order();
    // 只会加载order模块Activity对应的类对象到内存,避免将所有模块的Activity对应的类对象加载到内存
    // 这就是处于性能优化(准确的说是内存优化),要有分组保存、获取的原因
    Map<String, Class<? extends ARouterLoadPath>> groupMap = loadGroup.loadGroup();
    // app--->order
    Class<? extends ARouterLoadPath> clazz = groupMap.get("order");
    try {
        ARouterLoadPath path = clazz.newInstance();
        Map<String, RouterBean> pathBean = path.loadPath();
        // 获取/order/OrderActivity
        RouterBean routerBean = pathBean.get("/order/OrderActivity");
        if (routerBean != null) {
            Intent intent = new Intent(this, routerBean.getClazz());
            intent.putExtra("name", "xpf");
            startActivity(intent);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

首先实例化路由组文件,调用loadGroup方法获取保存的order模块的路径文件,通过它可以获取order模块Activity对应的类对象即class对象,然后实现跳转。如注释处所描述的,此时personal模块的所有Activity对应的类对象都不会加载到内存,这就是在性能方面的一个小优化,准确的说是内存优化。如果模块越多,每个模块的Activity越多,这个优化的作用就明显。只有需要进行跳转的时候,才会去加载对应模块Activity的类对象。

效果演示:

本文分析组件化的路由架构思路,也就是我们要通过APT生成什么样的文件,并手动实现演示可行性。下一篇将分析通过APT生成具体相关路由的类文件来实现。
代码链接:https://github.com/xpf-android/Moudlar_ARouter

你可能感兴趣的:(Android组件化实战六:路由架构设计)