Android 组件化使用 ARoute 实现组件化 ( ARoute 初始化 及 界面跳转 源码分析 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 组件化使用 ARoute 实现组件化 ( ARoute 初始化 及 界面跳转 源码分析 )相关的知识,希望对你有一定的参考价值。
组件化系列博客 :
- 【Android 组件化】从模块化到组件化
- 【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )
- 【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )
- 【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
- 【Android 组件化】路由组件 ( 路由组件结构 )
- 【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
- 【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
- 【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
- 【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
- 【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
- 【Android 组件化】路由组件 ( 组件间共享的服务 )
- 【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
- 【Android 组件化】路由组件 ( 运行时获取 注解处理器 生成的路由表 )
- 【Android 组件化】路由组件 ( 路由框架概述 )
- 【Android 组件化】路由组件 ( 页面跳转参数依赖注入 )
- 【Android 组件化】使用 ARoute 实现组件化 ( 完整组件化项目框架 )
一、ARoute 初始化源码分析
引入了 ARoute 的应用 , 一般会在主应用的 Application 中的 onCreate 方法中初始化 ARoute ;
package kim.hsl.component;
import android.app.Application;
import com.alibaba.android.arouter.launcher.ARouter;
public class MyApplication extends Application {
public static MyApplication mApplication;
public MyApplication() {
super();
mApplication = this;
}
public static MyApplication getInstance() {
return mApplication;
}
@Override
public void onCreate() {
super.onCreate();
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(this); // 尽可能早,推荐在Application中初始化
}
public boolean isDebug(){
return BuildConfig.DEBUG;
}
}
其中
ARouter.init(this);
是 ARoute 初始化的核心方法 , 其调用了 com.alibaba.android.arouter.launcher.ARouter 类的 init 方法 , com.alibaba.android.arouter.launcher.ARouter 类是一个空壳类 , 实际的代码逻辑都定义在 com.alibaba.android.arouter.launcher._ARouter 类中 ;
package com.alibaba.android.arouter.launcher;
public final class ARouter {
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
}
在 ARoute 类的 init 方法中调用了 _ARoute 的 init 方法
_ARouter.init(application);
_ARoute 相关源码如下 :
final class _ARouter {
protected static synchronized boolean init(Application application) {
mContext = application;
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
return true;
}
}
其中的
LogisticsCenter.init(mContext, executor);
是核心的逻辑 , 在该方法中 , 加载了路由表 ,
路由表类是 注解处理器 在编译时生成的类 , 生成的目录是 " D:\\002_Project\\002_Android_Learn\\ComponentDemo\\app\\build\\generated\\ap_generated_sources\\debug\\out\\com\\alibaba\\android\\arouter\\routes " ;
生成的路由表示例 :
package com.alibaba.android.arouter.routes;
import com.alibaba.android.arouter.facade.enums.RouteType;
import com.alibaba.android.arouter.facade.model.RouteMeta;
import com.alibaba.android.arouter.facade.template.IRouteGroup;
import java.lang.Override;
import java.lang.String;
import java.util.Map;
import kim.hsl.component.MainActivity;
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$app implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/app/MainActivity", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/app/mainactivity", "app", null, -1, -2147483648));
}
}
生成的对应的 Root 表 , 作为路由表的索引 ;
package com.alibaba.android.arouter.routes;
import com.alibaba.android.arouter.facade.template.IRouteGroup;
import com.alibaba.android.arouter.facade.template.IRouteRoot;
import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.util.Map;
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("app", ARouter$$Group$$app.class);
}
}
LogisticsCenter.init(mContext, executor) 方法执行的操作就是创建 ARouter$$Group$$app
类 , 调用该类的 loadInto 方法 , 导入路由表 , 将路由表加载到内存中 ;
二、ARoute 界面跳转源码分析
ARoute 使用时的示例如下 , 在该 Activity 类中 , 涉及到注解使用 , 界面跳转 ;
package kim.hsl.component;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
Log.i(TAG, "跳转到 Module1");
ARouter.getInstance().build("/module1/Module1Activity").navigation();
finish();
}
}
当调用到
ARouter.getInstance().build("/module1/Module1Activity").navigation();
代码进行界面跳转时 ,
public final class ARouter {
/**
* Build the roadmap, draw a postcard.
*
* @param path Where you go.
*/
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
}
ARouter.getInstance().build 方法实际上调用的是 _ARoute 的 build(String path) 方法 , 在 该方法中又调用了 build 的重载函数 build(String path, String group, Boolean afterReplace) , 最终返回了一个跳卡 Postcard 对象 ;
final class _ARouter {
/**
* Build postcard by path and default group
*/
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
// 不能传入空字符串地址 , 否则直接报异常
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
// 核心是调用了 build 的重载函数
// extractGroup 函数的作用明显是取出路径中的分组 , 就是前两个 / 之间的字符串内容
return build(path, extractGroup(path), true);
}
}
/**
* Build postcard by path and group
*/
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 {
if (!afterReplace) {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
}
// 最终创建了一张跳卡
return new Postcard(path, group);
}
}
}
跳转的实际操作是调用的跳卡的 navigation 方法 , 此时该跳卡中 , 只有 path 路由地址 , group 路由分子名称 , 其它信息还是空的 ;
public final class Postcard extends RouteMeta {
public Postcard(String path, String group) {
this(path, group, null, null);
}
/**
* Navigation to the route with path in postcard.
* No param, will be use application context.
*/
public Object navigation() {
return navigation(null);
}
/**
* Navigation to the route with path in postcard.
*
* @param context Activity and so on.
*/
public Object navigation(Context context) {
return navigation(context, null);
}
/**
* Navigation to the route with path in postcard.
*
* @param context Activity and so on.
*/
public Object navigation(Context context, NavigationCallback callback) {
return ARouter.getInstance().navigation(context, this, -1, callback);
}
}
其中的 NavigationCallback 参数 , 传入一个监听回调接口 , 可以监听跳转操作是否完成了 ;
/**
* Callback after navigation.
*
* @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
* @version 1.0
* @since 2016/9/22 14:15
*/
public interface NavigationCallback {
/**
* Callback when find the destination.
*
* @param postcard meta
*/
void onFound(Postcard postcard);
/**
* Callback after lose your way.
*
* @param postcard meta
*/
void onLost(Postcard postcard);
/**
* Callback after navigation.
*
* @param postcard meta
*/
void onArrival(Postcard postcard);
/**
* Callback on interrupt.
*
* @param postcard meta
*/
void onInterrupt(Postcard postcard);
}
调用 Postcard 跳卡对象的 navigation() 方法 , 之后调用了一系列的 navigation 重载方法 , navigation(Context context) , navigation(Context context, NavigationCallback callback) , 最终又调用了 ARouter.getInstance().navigation(context, this, -1, callback) 方法 ;
在 ARouter 的 navigation 方法中 , 依旧是调用了 _ARoute 的 navigation 方法 ;
public final class ARouter {
/**
* Launch the navigation.
*
* @param mContext .
* @param postcard .
* @param requestCode Set for startActivityForResult
* @param callback cb
*/
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}
}
跳卡 Postcard 对象中目前有 路由地址 , 路由分组 两个信息 , 先调用
LogisticsCenter.completion(postcard);
函数, 将跳卡 Postcard 对象补全 , 最重要的是该路由地址对应的 Class 类对象 , 通过之前 ARoute 初始化到内存的路由表补充跳卡中的数据 ;
然后判断该跳转是否是绿色通道 , 如果是继续执行跳转 ;
如果不是 , 则触发拦截器 , 拦截器判定未通过 , 则中断跳转 , 拦截器判定通过 , 则继续执行跳转 ;
这里的拦截器一般用于权限鉴定 , 比如用户是否购买会员 , 是否购买服务 , 是否拥有权限等等 ;
拦截器的详细用法自行去 GitHub 上查看 ;
最终调用 _navigation 方法进行跳转 ;
在 _navigation 方法中 , 跳卡 Postcard 的 Activity 跳转就是 创建 Intent , 并执行 startActivity 方法进行界面跳转 ;
final class _ARouter {
/**
* Use router navigation.
*
* @param context Activity or null.
* @param postcard Route metas
* @param requestCode RequestCode
* @param callback cb
*/
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
try {
// 补充跳卡数据
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
if (debuggable()) {
// Show friendly tips for user.
runInMainThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "There's no route matched!\\n" +
" Path = [" + postcard.getPath() + "]\\n" +
" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
}
});
}
if (null != callback) {
callback.onLost(postcard);
} else {
// No callback for this invoke, then we use the global degrade service.
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
// 此处说明跳卡的数据已经补全 , 继续进行后续跳转工作
if (null != callback) {
callback.onFound(postcard);
}
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
// 如果不是绿色通道 , 则需要经过拦截器 , 如购买会员 , 权限等
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
/**
* Continue process
* 拦截器没有进行拦截 , 则继续进行跳转
* @param postcard route meta
*/
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
/**
* Interrupt process, pipeline will be destory when this method called.
* 拦截器拦截成功 , 则中断跳转
* @param exception Reson of interrupt.
*/
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exceptionAndroid Gradle 插件组件化中的 Gradle 构建脚本实现 ④ ( 使用路由实现组件间通信 | 引入 ARoute 框架 | Gradle 构建脚本优化问题 )
错误记录Android Studio 集成 ARoute 编译报错 ( 兼容 support 库和 androidx 库 | add ‘tools:replace=“android:appCo )