引入了 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
app 类 , 调用该类的 loadInto 方法 , 导入路由表 , 将路由表加载到内存中 ;
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 : " + exception.getMessage());
}
});
} else {
// 如果是绿色通道 , 则直接进行跳转
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
case ACTIVITY:
// Build intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// Set Actions
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
// Navigation in main looper.
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
case PROVIDER:
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
// 从跳卡中取出 , 反射获取对象
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
if (instance instanceof Fragment) {
((Fragment) instance).setArguments(postcard.getExtras());
} else if (instance instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
}
return instance;
} catch (Exception ex) {
logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
}
case METHOD:
case SERVICE:
default:
return null;
}
return null;
}
}
插个插曲 , 分析下从内存中查找路由信息并填充到 跳卡 Postcard 对象的过程 ;
在 LogisticsCenter 中获取跳卡 Postcard 完整数据的方法 , 首先从 Warehouse.routes 中获取相关数据 , 之前 ARoute 的 init 初始化方法中将路由表加载到了内存中的该 Warehouse 对应的静态成员中 , 这里直接从该静态成员中获取 路由 数据 ;
如果从 Warehouse 中获取 路由信息 失败 , 说明路由表还没有加载 , 那么先加载路由表 , 路由表加载成功后 , 再获取跳卡对应的路由信息 , 并填充到 跳卡 Postcard 对象中 ;
public class LogisticsCenter {
/**
* Completion the postcard by route metas
*
* @param postcard Incomplete postcard, should complete by this method.
*/
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) { // Maybe its does't exist, or didn't load.
// 如果路由表还没有加载 , 此时加载路由表
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta.
// 如果再次加载失败 , 直接报异常退出
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// 路由表加载成功
// Load route and cache it into memory, then delete from metas.
try {
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
// 将路由表加载到内存中
iGroupInstance.loadInto(Warehouse.routes);
// 将路由表的索引信息从内存中移除 , 节省内存
Warehouse.groupsIndex.remove(postcard.getGroup());
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
completion(postcard); // Reload
}
} else {
// 获取到了路由信息 , 直接设置到跳卡中
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
if (null != rawUri) { // Try to set params into bundle.
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
// Set value by its type, just for params which annotation by @Param
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}
// Save params name which need auto inject.
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
// Save raw uri
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must implement IProvider
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
postcard.setProvider(instance);
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
}
博客源码 :