1.Postcard解析
- Postcard(明信片),继承与RouteMeta,在路由流程中起到定位提供类的作用,项目之中的所有跳转信息类都是基于此类,并提供了一些跳转能力
RouteMeta
private RouteType type; // 路由类型,支持如下:
// ACTIVITY(0, "android.app.Activity"),
// SERVICE(1, "android.app.Service"),
// PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
// CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
// BOARDCAST(-1, ""),
// METHOD(-1, ""),
// FRAGMENT(-1, "android.app.Fragment"),
// UNKNOWN(-1, "Unknown route type");
private Element rawType; // 路由之中的原始类型
private Class<?> destination; // 跳转目标类
private String path; // 路由地址
private String group; // 路由分组
private int priority = -1; // 优先级,数字越小,优先级越高
private int extra; // 额外数据
private Map<String, Integer> paramsType; // 参数
private String name; // 名称
private Map<String, Autowired> injectConfig;// 缓存注入配置
Postcard
// Base
private Uri uri; //Uri
private Object tag; // 标签为某些错误做准备。是内部参数,请勿使用
private Bundle mBundle; // 数据转换Bundele
private int flags = 0; // 路由标志
private int timeout = 300; // 超时时间
private IProvider provider; // 如果PostCard是Provider,则用于传递数据
private boolean greenChannel; // 绿色通道,true则拦截器失效
private SerializationService serializationService; // 内部使用的序列化服务
private Context context; // 上下文
private String action; // 动作
// 动画处理
private Bundle optionsCompat;
private int enterAnim = -1;
private int exitAnim = -1;
Postcard.navigation()
-
PostCard还提供了一系列跳转导航方法,其实内部都调用到了**ARouter.getInstance().navigation(mContext, this, requestCode, callback)**方法,最终实现至_ARouter.getInstance().navigation(mContext, postcard, requestCode, callback)方法之中
_ARouter其实才是真正实现了相关功能的类
-
_ARouter.getInstance().navigation()代码实现如下:
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)) {
return null;
}
postcard.setContext(null == context ? mContext : context);
try {
//物流中心预处理postcard,内部对postcard实现了完整的组装
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
//Debug专用处理
if (debuggable()) {
//如果postcard预处理失败则提示用户路由不匹配
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();
}
});
}
// 如果有callBack实现,则调用onLost回调
if (null != callback) {
callback.onLost(postcard);
} else {
// 如果没有具体的实现则启用全局降级服务进行处理
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
// 如果降级服务也没有预声明则调用onLost回调
if (null != degradeService) { degradeService.onLost(context, postcard); }
}
return null;
}
// 找到对应目的地则执行onFound回调
if (null != callback) { callback.onFound(postcard); }
// 如果不是绿色通道,则执行拦截器处理
if (!postcard.isGreenChannel()) {
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
_navigation(postcard, requestCode, callback);
}
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) { callback.onInterrupt(postcard);}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
}
});
} else {
// 否则直接执行_navigation()处理
return _navigation(postcard, requestCode, callback);
}
return null;
}
如果目的地存在,无论是否绿色通道,最终实现都在**_navigation(postcard, requestCode, callback)**方法之中
_navigation(postcard, requestCode, callback)
- 方法内部会根据类型进行分类,最终调用Android系统实现,例如如果类型是Activity,则最终调用startActivity方法。
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();
switch (postcard.getType()) {
// Activity 类型处理
case ACTIVITY:
// 组装 Intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
int flags = postcard.getFlags();
if (0 != flags) {
intent.setFlags(flags);
}
if (!(currentContext instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
// 最终在主线程调用 startActivity
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
// Provider 类型处理
case PROVIDER:
// 直接返回
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
// 获取 fragmentMeta
Class<?> fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
// 普通 Fragment 处理
if (instance instanceof Fragment) {
((Fragment) instance).setArguments(postcard.getExtras());
// V4 Fragment 处理
} else if (instance instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
}
// 返回 Fragment
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;
}
总结
- 首先Arouter根据最终目的地以及对应跳转参数创建PostCard,PostCard内部包含了全部属性
- 最终通过PostCard的navigation()方法进行跳转
- navigation()方法内部最终会调用_ARouter.getInstance().navigation()的实现
- _ARouter.getInstance().navigation()内部首先会通过LogisticsCenter实现物流预处理PostCard,如果是合法路径则继续
- 如果是绿色通道则不执行拦截器处理
- 如果不是绿色通道则执行拦截器处理
- 最终调用_navigation()方法
- _navigation()内部会根据类型进行区分
- 如果是Activity,则根据PostCard装载Intent,最终调用StartActivity()
- 如果是Provider直接返回PostCard中的Provider
- 如果是Fragment则区分是V4还是普通Fragment,最终返回实例,如果找不到实例则提示异常
2.Annotation注解处理器
Arouter强大的一点就是通过注解实现了许多重复的代码自动填充,提供的注解如下:
- Route:标记页面可以通过路由器进行路由
- Interceptor:标记一个拦截器进行路线拦截
- Autowired:自动实现参数装配
每一个注解肯定对应这一个注解处理器,使得所有标记对应注解的类可以自动实现其能力
注解处理器都是通过javapoet和auto-service实现了面向切面编程的能力
Route
我们直接看process之中的parseRoutes方法,代码中只保留了关键部分
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
......
if (CollectionUtils.isNotEmpty(routeElements)) {
......
// 根据传入的所有标记Route的元素进行分析,最终返回RouteMeta添加至Map之中
for (Element element : routeElements) {
// Activity or Fragment
if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
.....
if (types.isSubtype(tm, type_Activity)) {
//创建对应 Activity 类型的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
} else {
//创建对应 Fragment 类型的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), paramsType);
}
routeMeta.setInjectConfig(injectConfig);
} else if (types.isSubtype(tm, iProvider)) {
//创建对应 Provider 类型的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
} else if (types.isSubtype(tm, type_Service)) {
//创建对应 Service 类型的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
} else {
throw new RuntimeException("The @Route is marked on unsupported class, look at [" + tm.toString() + "].");
}
//最终将 RouteMeta 添加到 groupMap
categories(routeMeta);
}
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
Map<String, List<RouteDoc>> docSource = new HashMap<>();
// 根据 groupMap 列表开始生成对应JAVA代码
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
......
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
.....
switch (routeMeta.getType()) {
case PROVIDER:
.....
//如果是Provider类型则要对其进行缓存
break;
default:
break;
}
StringBuilder mapBodyBuilder = new StringBuilder();
Map<String, Integer> paramsType = routeMeta.getParamsType();
Map<String, Autowired> injectConfigs = routeMeta.getInjectConfig();
if (MapUtils.isNotEmpty(paramsType)) {
List<RouteDoc.Param> paramList = new ArrayList<>();
for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
// 开始真正的写入JAVA代码
mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
RouteDoc.Param param = new RouteDoc.Param();
Autowired injectConfig = injectConfigs.get(types.getKey());
param.setKey(types.getKey());
param.setType(TypeKind.values()[types.getValue()].name().toLowerCase());
param.setDescription(injectConfig.desc());
param.setRequired(injectConfig.required());
paramList.add(param);
}
routeDoc.setParams(paramList);
}
String mapBody = mapBodyBuilder.toString();
}
.................
}
}
@Route总结
-
获取到所有的被注解Route的类,生成对应的RouteMeta,分组放到groupMap中,key为group name, value为支持排序放入的的Set中
-
遍历groupMap中所有的Set的所有RouteMeta (所以是个双层for循环)生成对应代码。
生成的对应代码如下:
public class ARouter$$Group$$test implements IRouteGroup { @Override public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class, "/test/webview", "test", null, -1)); } }
Autowired
- Autowired其实也是通过注解处理器实现的,代码比较简单,其实生成的就是Intent的自动组装。只不过比较巧妙的是,我们在使用Arouter时都要调用ARouter.getInstance().inject(this)代码,其实生成的代码就是inject的重写intent的自动组装。
生成的代码如下:
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
Test1Activity substitute = (Test1Activity)target;
// Intent 自动组装
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
// 中间还有一部分安全检查例如要使用序列化则要实现SerializationService
substitute.url = substitute.getIntent().getExtras() == null ? substitute.url : substitute.getIntent().getExtras().getString("url", substitute.url);
substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
}
}
@Autowired总结
- 在Activity的变量上标注,注解处理器会在编译阶段扫描有被Autowired注解标注的变量,根据这个类和变量的情况生成一份Java代码,其中最主要会有一个inject方法,完成对相关变量的解析赋值,然后在Activity的onCreate靠前位置调用对应inject方法即可。这个注解主要目的在于省去了手动编写解析Intent参数的代码。
Interceptor
- 拦截器的实现其实主要是在InterceptorServiceImpl类之中的两个方法
doInterceptions
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
checkInterceptorsInitStatus();
if (!interceptorHasInit) {
//如果在处理拦截还没有初始化完成,则抛出初始化时间太长异常
callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
return;
}
//在异步线程逐个调用_execute()实现拦截
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
_execute(0, interceptorCounter, postcard);
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
//判断是否超时
if (interceptorCounter.getCount() > 0) {
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
// 异常处理
} else if (null != postcard.getTag()) {
callback.onInterrupt((Throwable) postcard.getTag());
// 继续处理
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
_execute
private static void _execute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
iInterceptor.process(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
counter.countDown();
// 内部递归调用,并调整index数值
_execute(index + 1, counter, postcard);
}
@Override
public void onInterrupt(Throwable exception) {
postcard.setTag(null == exception ? new HandlerException("No message.") : exception);
counter.cancel();
}
});
}
}
@Interceptor总结
- 在doInterceptions()方法之中,通过异步线程实现调用_execute方法
- 内部还有异常以及超时处理
- _execute()之中通过递归调用,并且跳转index实现拦截器逐个处理