Android

您所在的位置:网站首页 安卓路由追踪代码 Android

Android

2024-07-15 15:45| 来源: 网络整理| 查看: 265

Android-Router路由框架实战1. Router框架简介

对于一个大型项目来说,双向/循环依赖的场景非常常见,因此 Router 几乎是必备的(或是作为核心通信工具)。简单来说,Router 是基于 中介者模式 的组件间通信框架,其定义了组件的输入和输出标准,使得通信双方从「组件 - 组件」解耦为「组件 - Router」。

一个典型的双向依赖场景:假设一个项目包含 module_user、module_util 等 Module。(1)当用户登录时,module_user 需要依赖 module_util 使用某些工具;(2)而工具模块 module_util 中网络组件又需要使用 module_user 的用户信息鉴权。

如果使用传统的解决方案,无外乎两个原则:减小模块颗粒度、抽象公共逻辑。例如抽象出一个独立的 module_userinfo 作为底层公共依赖。虽然同样可以解决问题,但当越来越多的 Module 出现互相依赖时,这种改造的复杂度可以说是灾难级的。 使用 Router 框架,则只需要 module_user 定义用户信息的输出 Router.set("userInfo", userInfo);module_util 根据约定的方式读取 Router.get("userInfo") 即可。

当然该例只是为了表示 Router 的核心思路,实际的交互方式需要根据项目自定义。

目前应用较普遍的是阿里开源的 ARouter 框架。

1.1 ARouter的基本原理

ARouter 最开始是为了页面跳转之间解耦,本质上它提供了通过 String 的「路径 Path」对应到 Activity / Fragment 的路由表。其核心是通过 APT 在编译时自动检索添加了 @Route(path="/XXX/XXX") 注解的 Activity,并以对应的 Path 为 Key 生成 Map,然后在运行时根据 Map 存储的路由信息跳转。ARouter 要求 Path 必须包括至少两级,例如:/main/sub,将 main 称为主路径;sub 称为子路径。一个主路径可以包括多个子路径,例如:/main/sub, /main/sub2 等。

当项目很庞大或页面数量很多时就会生成一个巨大的路由表,为此 ARouter 做了 分段懒加载 的优化,即运行时不会立即将所有路由信息都加载进内存,而是在发起一个路由请求时,先读取缓存,如果缓存没有再懒加载目标主路径下的所有子路由信息。

1.2 ARouter编译时处理

ARouter 在编译时会通过 APT 生成两个表:

(1)对每个应用了 ARouter APT 的 Module,检索所有添加了 @Route 注解的页面组件(Activity / Fragment),并在 Module 下生成每个具体的 Path 对应页面的表 atlas。

12345678910111213141516// module_splash 目录下的 ADSActivity 会生成以下路由表:public class EaseRouter_Group_splash implements IRouteRoot { @Override public void loadInto(Map atlas) { atlas.put("/splash/ads", RouteMeta.build(RouteMeta.Type.ACTIVITY, ADSActivity.class, "/splash/ads", "splash")); }}// module_user 目录下的 LoginActivity 和 RegisterActivity 会生成以下路由表:public class EaseRouter_Group_user implements IRouteRoot { @Override public void loadInto(Map atlas) { atlas.put("/user/login", RouteMeta.build(RouteMeta.Type.ACTIVITY, LoginActivity.class, "/user/login", "user")); atlas.put("/user/register", RouteMeta.build(RouteMeta.Type.ACTIVITY, RegisterActivity.class, "/user/register", "user")); }}

(2)将所有路由信息生成主路径对应每个实际路由表 atlas 的分段表:

1234567public class EaseRouter_Root_app implements IRouteRoot { @Override public void loadInto(Map compiledClass) { ......}

然而这段代码实际上只有 BlankInterface.java 才能被编译通过,编译 BaseServiceInterface.java 时会抛出以下异常:

12345678910111213141516171819/Project/module_demo/src/main/java/priv/demo/DemoServiceInterface.java:3: error: package androidx.lifecycle does not existimport androidx.lifecycle.Lifecycle; ^/Project/module_demo/src/main/java/priv/demo/DemoServiceInterface.java:4: error: package priv.base does not existimport priv.base.BaseServiceInterface; ^/Project/module_demo/src/main/java/priv/demo/DemoServiceInterface.java:6: error: cannot find symbolpublic interface DemoServiceInterface extends BaseServiceInterface { ^ symbol: class BaseServiceInterface/Project/module_demo/src/main/java/priv/demo/DemoServiceInterface.java:7: error: package Lifecycle does not exist void onEventReceived(Lifecycle.Event event); ^4 errorsFAILURE: Build failed with an exception.

这是因为 DemoServiceInterface.java 依赖的类并没有被 Compile,因此其编译时在工作目录下读取不到 import 的内容。

3.2.3 Plugin重编译方案失败总结 由于 Router 是一个通用框架,因此需要被拷贝的类可能会具有各种各样的依赖,针对每个依赖都递归编译是不现实的; 该方案从一开始就不合理,因为其会导致大量类被编译多次,这对一个大型项目的编译速度堪称毁灭性打击。 4. 实现自定义Router

通过上文分析可以明确自定义 Router 需要实现以下目标:

通过 APT 自动收集符合条件的接口及实现类映射。 通过 Transform 自动注册映射。 4.1 APT自动收集接口与实现类的映射4.2 Transform自动注册映射 参考文献

ARouter:

Android路由框架ARouter的集成、基本使用以及踩坑全过程 ARouter原理剖析及手动实现

Gradle:

ADDING PARAMETERS TO A GRADLE PLUGIN Gradle plugin with reflections Maven Publish Plugin How to build some java files to one jar using gradle java-plugin?

其他:

使用ASTParser(抽象语法树)获取类属性注释 获取Java接口的所有实现类 How do I programmatically compile and instantiate a Java class?


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3