ARouter.getInstance().build(RoutePath.USER_HOME).navigation()
复制代码
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
build()
方法会通过 ARouter
中转调用到 _ARouter
的 build()
方法,最终返回一个 Postcard
对象
/**
- 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) {
//用于路径替换,这对于某些需要控制页面跳转流程的场景比较有用
//例如,如果某个页面需要登录才可以展示的话
//就可以通过 PathReplaceService 将 path 替换 loginPagePath
path = pService.forString(path);
}
//使用字符串 path 包含的第一个单词作为 group
return build(path, extractGroup(path));
}
}
/**
- Build postcard by path and group
*/
protected Postcard build(String path, String group) {
if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
throw new HandlerException(Consts.TAG + “Parameter is invalid!”);
} else {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return new Postcard(path, group);
}
}
复制代码
返回的 Postcard
对象可以用于传入一些跳转配置参数,例如:携带参数 mBundle
、开启绿色通道 greenChannel
、跳转动画 optionsCompat
等
public final class Postcard extends RouteMeta {
// Base
private Uri uri;
private Object tag; // A tag prepare for some thing wrong.
private Bundle mBundle; // Data to transform
private int flags = -1; // Flags of route
private int timeout = 300; // Navigation timeout, TimeUnit.Second
private IProvider provider; // It will be set value, if this postcard was provider.
private boolean greenChannel;
private SerializationService serializationService;
}
复制代码
Postcard
的 navigation()
方法又会调用到 _ARouter
的以下方法来完成 Activity 的跳转。该方法逻辑上并不复杂,注释也写得很清楚了
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.
//用于执行跳转前的预处理操作,可以通过 onPretreatment 方法的返回值决定是否取消跳转
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;
}
//由于本例子的目标页面是 Activity,所以只看 ACTIVITY 即可
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
//Destination 就是指向目标 Activity 的 class 对象
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;
··· //省略其它类型判断
}
return null;
}
}
复制代码
navigation
方法的重点在于 LogisticsCenter.completion(postcard)
这一句代码。在讲 ARouter 初始化流程的时候有讲到:等到后续需要跳转到 group
为 account
的页面时,就会再来反射调用 ARouter$$Group$$account
的 loadInto
方法,即按需加载,等到需要的时候再来获取详细的路由对应信息
completion
方法就是用来获取详细的路由对应信息的。该方法会通过 postcard
携带的 path 和 group 信息从 Warehouse
取值,如果值不为 null 的话就将信息保存到 postcard
中,如果值为 null 的话就抛出 NoRouteFoundException
/**
-
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) { //为 null 说明目标类不存在或者是该 group 还未加载过
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta.
if (null == groupMeta) {
//groupMeta 为 null,说明 postcard 的 path 对应的 group 不存在,抛出异常
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