“终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解

本文深入解析ARouter组件化框架的工作原理,包括路由认知、原理解析,重点剖析构建PostCard、路由过程中的拦截器、路由元信息收集等关键环节。ARouter如何在组件间实现无耦合的页面跳转和通信,以及如何通过编译时生成的帮助类进行路由信息加载。通过对ARouter的深入理解,有助于提升Android组件化开发能力。
摘要由CSDN通过智能技术生成

前言

在我之前的组件化文章《“终于懂了” 系列:Android组件化,全面掌握!》中,提到为了实现组件化要解决的几个问题点,其中 页面跳转组件间通信 的问题是使用了 ARouter 这个框架来解决的。ARouter确实是专门用于做组件化改造,官方是这么介绍的:

一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦

关于组件化的知识已在上面文章中全面介绍了。那么是时候对 ARouter 这个强大的框架做一个解析了:它是如何做到 页面跳转、组件间通信 的?我们能从ARrouter中学到哪些东西?

而当时也确实承诺了有机会要写一篇ARouter的文章:

ARouter还有很多进阶用法,有机会我也针对ARouter写一篇全面分析

由于内容预计较多,分为三篇,分别介绍 ARouter的实现原理、框架使用到的相关通用技术:

  • “终于懂了” 系列:组件化框架 ARouter 完全解析(一)原理全解
  • “终于懂了” 系列:组件化框架 ARouter 完全解析(二)APT—帮助类生成
  • “终于懂了” 系列:组件化框架 ARouter 完全解析(二)AGP/Transform—动态代码注入

本篇就先梳理ARouter的实现原理,看看它是如何做到跨组件跳转页面、获取服务。

感谢继续关注和支持~

一、路由认知

ARouter从命名即可知,这是一个路由框架。那么路由是个啥呢?

路由routing)就是通过互联的网络把信息源地址传输到目的地址的活动。-- 百科
可见 路由 是个动词,这是网络传输中的概念,完成路由这个操作的实体设备就是 路由器(Router)。

另外,生活中的 信件邮寄 也可以理解为一个 路由过程:邮局把信件从邮寄方 传输到接收人的手上。首先 邮寄方 和 接收人 是无法接触的(无耦合依赖),只能通过 邮局这个第三方 完成邮寄;邮局根据信封上的地址,例如 “深圳市 深圳大学粤海校区”,决定分发到 开往深圳的车上,然后深圳的邮递员找到 深圳大学粤海校区 对应的 "南山区南海大道3688号”,最终找到接收人。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HGOmWj6M-1658750174332)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c3428ead70384bd4a3856937338889a9~tplv-k3u1fbpfcp-watermark.image?)]

对应地, ARouter 也是个“路由器”,也是个“邮政系统”。通行根据组件化介绍的,ARouter 帮助 无相互依赖的组件间 进行跳转和通信。

抽象一下,邮局、ARouter 都是 路由系统 ——— 给 无依赖的双方 提供 通信和路由的能力。

官方文档 有详细的引入和各种功能使用介绍,包括基础使用步骤、参数解析、拦截器、服务获取等进阶用法。这里不再搬运。

二、原理解析

使用ARouter在进行Activity跳转非常简单:初始化ARouter、添加注解@Route、发起路由。

// 在module app中
//1.初始化SDK
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
// moduleA
// 2.在支持路由的页面上添加注解(必选)
// 路径注意至少需有两级,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
   
    ...
}
// moduleB(没有依赖 moduleA)
// 3.发起路由跳转
ARouter.getInstance().build("/test/activity").navigation();

这样就使得 没有依赖moduleA的moduleB能跳转到moduleA的Activity了。服务获取也是类似简单的代码就可实现。

那么 ARouter 是如何做到只通过简单2步 就完成 解耦组件间的路由操作呢?我们通过源码一步步理解。

2.1 构建PostCard

我们知道 想要跳转Activity最终必定是走到了 startActivity(intent)方法,而intent是一般需要目标Activity的Class。所以我们猜想 navigation()中应该是有寻找目标Activity的Class这一过程的。

下面就来跟踪源码分析这一过程。先看ARouter.getInstance():

public static ARouter getInstance() {
   
    if (!hasInit) {
    // 未初始化则报异常
        throw new InitException("ARouter::Init::Invoke init(context) first!");
    } else {
   
        if (instance == null) {
   
            synchronized (ARouter.class) {
   
                if (instance == null) {
   
                    instance = new ARouter();
                }
            }
        }
        return instance;
    }
}

获取ARouter单实例,没有初始化则报异常。再看它的build(string)方法:

public Postcard build(String path) {
   
    return _ARouter.getInstance().build(path);
}

这里是调用了 _ARouter 的同名方法,返回了 Postcard(意为明信片)。ARouter实际是使用了外观模式(设计模式的一种),其所有方法都是调用了_ARouter的同名方法。 进入_ARouter:

protected Postcard build(String path) {
   
    if (TextUtils.isEmpty(path)) {
    //path不能为空
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
   
        //path替换,这是预处理
        PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
        if (null != pService) {
   
            path = pService.forString(path);
        }
        return build(path, extractGroup(path), true);
    }
}

这里对path做了空校验和预处理替换。如果想重写path,可以写一个PathReplaceService实现类。接着又走到重载方法:

protected Postcard build(String path, String group, Boolean afterReplace) {
   
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
   
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
   
        ...
        return new Postcard(path, group);
    }
}

其中参数group是通过extractGroup(path)获取,也就是path的第一级,即"/test/activity"中的"test"。group的作用是作为路由的默认分组。

路由中的分组概念:

  • SDK中针对所有的路径(/test/1、/test/2)进行分组,分组只有在分组中的某一个路径第一次被访问的时候,该分组才会被初始化
  • 可以通过 @Route 注解主动指定分组,否则使用路径中第一段字符串(/*/)作为分组
  • 注意:一旦主动指定分组之后,应用内路由需要使用 ARouter.getInstance().build(path, group) 进行跳转,手动指定分组,否则无法找到
    @Route(path = "/test/1", group = "app")

最后返回创建的Postcard实例。Postcard是明信片的意思,承载了一次跳转/路由 需要的所有信息,它继承自路由元信息 RouteMeta

public final class Postcard extends RouteMeta {
   

    // Base
    private Uri uri;                //使用Uri方式发起的路由
    private Object tag;             // A tag prepare for some thing wrong. inner params, DO NOT USE!
    private Bundle mBundle;         //启动activity的传入的Bundle
    private int flags = 0;         // 启动activity的Flags
    private int timeout = 300;      // 路由超时时间
    private IProvider provider;     // 如果是获取provider,就有值
    private boolean greenChannel;  //是绿色通道
    private SerializationService serializationService;
    private Context context;        //context
    private String action;          //启动activity的action
    
    // activity转场动画相关
    private Bundle optionsCompat;
    private int enterAnim = -1;
    private int exitAnim = -1;
    
    public Postcard(String path, String group) {
   
        this(path, group, null, null);
    }

    public Postcard(String path, String group, Uri uri, Bundle bundle) {
   
        setPath(path);
        setGroup(group);
        setUri(uri);
        this.mBundle = (null == bundle ? new Bundle() : bundle);
    }
    ...
}
public class RouteMeta {
   
    private RouteType type;         // 路由类型;activity、service、fragment、IProvider等,编译时会根据被@Route注解的类的类型来设置
    private Element rawType;        // 路由原始类型,在编译时用来判断
    private Class<?> destination;   // 目的地:具体的 XxxActivity.class等
    private String path;            // Path
    private String group;           // Group
    private int priority = -1;      // 优先级,越小优先级越高
    private int extra;              // Extra
    private Map<String, Integer> paramsType;  // 参数类型,例如activity中使用@Autowired的参数类型
    private String name; //路由名字,用于生成javadoc
    private Map<String, Autowired> injectConfig;  // 参数配置(对应paramsType).
}
  • Postcard:路由的信息。 理解为是生活中的明信片。继承自RouteMeta。例如Postcard中的mBundle等则是 明信片上寄件人写的 “你好,xxx 节日快乐!” 这种文字内容。
  • RouteMeta:路由元信息,即基础信息。 理解就是 明信片上的 收件人地址 这种必备的基础信息。 明信片上可以没有文字内容,但想要被邮寄就必须有收件人地址

2.2 路由过程

2.2.1 整体步骤

通过path构建了PostCard后调用了其navigation()方法,也就是开始了路由过程:

public Object navigation() {
   
    return navigation(null);
}
public Object navigation(Context context) {
   
    return navigation(context, null);
}
public Object navigation(Context context, NavigationCallback callback) {
   
    return ARouter.getInstance().navigation(context, this, -1, callback);
}

看到连续走了两个重载方法,最后走到ARouter的navigation方法,并且把自己传了进去。ARouter的navigation方法同样会走到_ARouter的同名方法:

 // @param context     Activity or null.
 // @param postcard    Route metas
 // @param requestCode RequestCode,startActivity的requestCode
 // @param callback    cb,路由回调:找到目的地、未找到、中断、到达
protected Object navigation(final Context context, final Postcard postcard, final int requestCode,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值