ARouter中Interceptor原理理解(一)
最近在实践jetpack的Navigation,由于google推荐使用一个activity 其余都是fragment来进行编程,所以打算借鉴阿里巴巴的开源路由框架ARouter打造一个基于Navigation 简化版的ARouter主要为了实现对需要登录信息页面入口的拦截,点击需要登录的页面检查本地token如果没有就先去登录,登陆完后进入目标页面。
接着上次对ARouter的这次带着疑问来进一步理解,疑问是:为什么我们能通过 ARouter.getInstance().build(xxx).navigation() 进行Activity的跳转的,ARouter又是如何通过 @Route(path = xxx) 来找到对应的activity的。
ARouter根据 ARouter.getInstance().build(xxx) 传入的path来对比我们Activity类上的@Route方法中的path对应的值在navigation()方法调用的时候来进行匹配找到Activity后再通过startActivity()或者startActivityForResult()
/**
* 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);
}
return build(path, extractGroup(path));
}
}
PathReplaceService.forString(path)可以先不管,PathReplaceService从字面意思可知是通过我们build传入的字符串进过PathRelaceService处理一下传给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中传入path和group字符串参数的构造函数
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);
}
PostCard是RouteMeta类的子类,Path和Gourp是RouteMeta的成员变量,
Bundle和Uri则是PostCard的成员变量
public class RouteMeta {
private RouteType type; // Type of route
private Element rawType; // Raw type of route
private Class<?> destination; // Destination
private String path; // Path of route
private String group; // Group of route
private int priority = -1; // The smaller the number, the higher the priority
private int extra; // Extra data
private Map<String, Integer> paramsType; // Param type
private String name;
public final class Postcard extends RouteMeta {
// Base
private Uri uri;
private Object tag; // A tag prepare for some thing wrong.
private Bundle mBundle;
PostCard中有多个navigation方法,
/**
* 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);
}
我们最常调用的
ARouter.getInstance().build(xxx).navigation()
等于Postcard postcard = ARouter.getInstance().build(xxx)
postcard.navigation()
无参的postcard.navigation()实际调用的postcard.navigation(null,null)等于
ARouter.getInstance().navigation(null,this,-1,null)由前文可知ARouter用了门面模式实际执行者是_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);
}
先跳过参数处理和拦截器部分的源码,_ARouter里真正执行的是_navigation(context, postcard, requestCode, callback);
看我们最熟悉的Activity的部分:
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;
代码几乎无难度,和源码有出入的地方在 startActivity(requestCode, currentContext, intent, postcard, callback);这个方法
/**
* Start activity
*
* @see ActivityCompat
*/
private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
if (requestCode >= 0) { // Need start for result
if (currentContext instanceof Activity) {
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
}
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
结合PostCard中的注解可知是对动画进行处理的逻辑
// Animation
private Bundle optionsCompat; // The transition animation of activity