辅助工具类生成;
- arouter-annotation: 项目中的注解Autowired,Interceptor,Route
- arouter-compiler: 过apt,javapoet 来实现编译器的辅助代码生成;
APT:APT(Annotation Processing Tool)是java的注解处理技术
javapoet: 是用于生成 .java 源文件的 Java Api
页面注册跳转
Group注册:
首先进行初始化
ARouter.init();
_ARouter.init(application)
LogisticsCenter.init(mContext, executor);
_ARouter 为整个Arouter 的实现类,此种模式为装饰者模式.客户端通过配置达成逻辑并进行解耦;
主要分析下:LogisticsCenter.init(mContext, executor);
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
//load by plugin first 先通Gradle 插件来实现。如果插件失败通过线程池来实现
loadRouterMap();
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
Set<String> routerMap;
// It will rebuild router map every times when debuggable.
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
// These class was generated by arouter-compiler.
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
PackageUtils.updateVersion(context); // Save new version name when router map update finishes.
} else {
logger.info(TAG, "Load router map from cache.");
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
startInit = System.currentTimeMillis();
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
// 实现的加载 loadInto
}
}
logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");
if (Warehouse.groupsIndex.size() == 0) {
logger.error(TAG, "No mapping files were found, check your configuration please!");
}
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
可以看到,测试环境加载所有 包名为 ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"; 的Dex 类信息文件;因为这是个非常消耗性能的操作;Arroter 提供了两周形式;一直为通过线程池;第二种为Glade 来实现; 并做了缓存机制来提升性能; 加载 SUFFIX_ROOT = "Root";UFFIX_INTERCEPTORS = "Interceptors";String SUFFIX_PROVIDERS = "Providers" 通过反射实例化对象并调用方法,将注解的一些元素添加到static集合中:
具体代码实现(通过辅助生成的代码如下)
在此已经完成model 组的注册; 这里有个bug 需要知道issue 目前新版Arouter 会有异常抛出,所以在使用的时候分组名称和当前的modelf名称分组一致:
A Module 中注解了/a/target1
B Module 中注解了/b/target2 /a/target3
A Module的apt会生成Arouter$$Group$$a\
B Module的apt会生成Arouter$$Group$$b 和 Arouter$$Group$$a
其中Arouter$$Group$$a是同包名同类名,因此打包apk的时候会覆盖,只保留其中一个类,进而导致A Module 的注解类无法跳转。
具体执行目标的注册
辅助的生成代码:
动态代码生成逻辑;
RouteProcessor
/*
Build input param name.
*/
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
/*
Build method : 'loadInto'
*/
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
RouteMeta,存储一些类的一些信息。RouteType 类的类型为枚举,group 组名,destination 目标类等;
页面跳转
执行跳转;
ARouter.getInstance().build("/test/activity2").navigation();
这里其实是一个 Postcard 继承 RouteMeta,携带了跳转的需要的各种信息,
其中 navigation 是调用到_Arouter.navigation;
PretreatmentService 跳转拦截,并可以做跳转前的逻辑处理; LogisticsCenter.completion(postcard);动态注册目标之外,还有对 postcard 的一些赋值;
callback.onFound(postcard); 跳转的处理的回调。丢失,到达等回调;
最终 实现跳转的是Arouter._navigation ,并没有什么过人之处,依然是使用的Android 的startActivity;
postcard.getDestination(),为跳转了类的目标,在上面说的页面注册赋值;
至此页面的跳转完成;
页面的数据接受;
到达页面后,会有控制反转,对属性进行一些赋值;
ARouter.getInstance().inject(this);
_ARouter.inject(thiz);
AutowiredServiceImpl 获取AutowiredService的具体实现;
然后通过具体的反射到辅助生成的类,进行数据的赋值;
辅助生成工具类为:AutowiredProcessor,生成类示例:
后来完成最终的赋值;
service
- 注册service 通过apt注册所有的服务到容器内;
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
- postcard 进行通道赋值 IProvider,这里有句postcard.greenChannel();所以拦截器对所有的service 是没有作用的;
3. 执行
navigation 获取到最终的 class type 调用到最终的service 的实现类后调用具体实现函数
protected <T> T navigation(Class<? extends T> service)
return (T) postcard.getProvider();
拦截器
InterceptorProcessor 和 Interceptor 为拦截器辅助代码生成器。在使用的时候我们可以面对切面编程aop做到很好的解耦
拦截逻辑
- 在 navigation 跳转的时候会进行一个 interceptorService 调用检测;
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(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(postcard, requestCode, callback);
}
postcard.isGreenChannel() 会有绿通道,在Build 的时候进行设置所有的拦截器不会调用;
- 看下 InterceptorService 的具体实现;
public void init(final Context context) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
iInterceptor.init(context);
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
}
}
interceptorHasInit = true;
logger.info(TAG, "ARouter interceptors init over.");
synchronized (interceptorInitLock) {
interceptorInitLock.notifyAll();
}
}
}
});
}
初始化所有的拦截器,并把拦截器放到 Warehouse.interceptors ,我们可以看到子线程进行的;完成初始化后通知主线程的,checkInterceptorsInitStatus 来检测是否初始化成功然后进行下一步的操作;
- 执行实践;
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;
}
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) { // Cancel the navigation this time, if it hasn't return anythings.
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) { // Maybe some exception in the tag.
callback.onInterrupt((Throwable) postcard.getTag());
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
- checkInterceptorsInitStatus : 等待初始化执行完成
- _execute(0, interceptorCounter, postcard); :具体执行拦截逻辑添加
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) {
// Last interceptor excute over with no exception.
counter.countDown();
_execute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know.
}
@Override
public void onInterrupt(Throwable exception) {
// Last interceptor execute over with fatal exception.
postcard.setTag(null == exception ? new HandlerException("No message.") : exception); // save the exception message for backup.
counter.cancel();
// }
}
});
}
}
我们从这里可以看到拦截器的代码是进行子线程,所以拦截器内不能直接做ui的展示和更新; 同时 _execute(index + 1, counter, postcard) 这里有个递归调用可以看出 Warehouse.interceptors 的存放顺序 决定了拦截器的执行顺序;通过init 可以发现 Warehouse.interceptorsIndex 决定了Warehouse.interceptors ; Warehouse.interceptors 的添加在动态代码内
InterceptorProcessor
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
if (CollectionUtils.isNotEmpty(elements)) {
logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");
// Verify and cache, sort incidentally.
for (Element element : elements) {
if (verify(element)) { // Check the interceptor meta
logger.info("A interceptor verify over, its " + element.asType());
Interceptor interceptor = element.getAnnotation(Interceptor.class);
Element lastInterceptor = interceptors.get(interceptor.priority());
if (null != lastInterceptor) { // Added, throw exceptions
throw new IllegalArgumentException(
String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
interceptor.priority(),
lastInterceptor.getSimpleName(),
element.getSimpleName())
);
}
interceptors.put(interceptor.priority(), element);
} else {
logger.error("A interceptor verify failed, its " + element.asType());
}
}
通过 interceptors.put(interceptor.priority(), element);可以看出在设置 @Interceptor(priority = 7) 数值越小 优先级越高;