前置知识
APT
Annotation Processing Tool,自定义注解处理器。
搞Android的基本上都知道这个吧。许多第三方库都使用了APT去实现自己的功能,比如butterknife,比如X2C,比如我们要讲的ARouter。
其基本做法是:
- 自定义编译期注解(比如ARouter源码中的arouter-annotation模块)
- 自定义AbstractProcessor,实现process方法,在该方法中扫描步骤1定义的注解,根据注解信息生成辅助文件(.java文件)(比如ARouter源码中的arouter-cmpiler模块)
- Runtime时期,通过反射创建辅助类(获取步骤2生成的文件的全路径,反射),调用辅助类中的方法(比如ARouter源码中的arouter-api模块)
自定义Gradle Plugin
一般是自定义gradle Transform + ASM,实现AOP,可以在编译期修改project和第三方依赖库中的class文件(比如ARouter源码中的arouter-gradle-plugin模块),与APT主要是生成.java文件不同,ASM操作的是.class文件。
自定义gradle Transform功能很强大,可以与ASM结合,修改.class,也可以操作资源文件(比如统一压缩图片,转png大图为webp等)。
至于ASM,基于修改.class文件,我们即可以用ASM来插桩统计方法耗时,也可以用来实现自动化埋点,甚至是修改第三方lib中的crash...
写在前面
使用方法可以看ARouter。
带着问题看源码,这里主要的问题是:
- 初始化都做了什么?
- ARouter是如何实现组件间的路由跳转的?
- 拦截器是如何生效的?
- IProvider 的实现机制
- ARouter的Gradle Plugin做了哪些优化?
初始化
ARouter.init(getApplication());
ARouter的核心方法。
ARouter#init
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.");
}
}
_ARouter#init
protected static synchronized boolean init(Application application) {
mContext = application;
//核心方法
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
//创建mainHandler
mHandler = new Handler(Looper.getMainLooper());
return true;
}
LogisticsCenter#init
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
//load by plugin first
//这是问题5的关键,该方法默认空实现(不使用Gradle plugin的时候)
//暂时跳过该方法,后面分析
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.
//如果是debug模式
//或者App版本有更新(这里比较的是versionName)
//重新加载路由表
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();
}
//更新sp中的versionName
//这里跟上面的PackageUtils.isNewVersion(context)对应
PackageUtils.updateVersion(context); // Save new version name when router map update finishes.
} else {
logger.info(TAG, "Load router map from cache.");
//从sp中取出缓存的路由表(扫描加载路由表是耗时的IO操作,因此使用缓存,提高加载速度)
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();
//遍历路由表
//初始化路由表的各个Group
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// This one of root elements, load root.
//如果是IRouteRoot的话(文件名以com.alibaba.android.arouter.routes.ARouter$$Root),反射创建IRouteRoot实例
//并执行其IRouteRoot#loadInto方法
((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的话(文件名以com.alibaba.android.arouter.routes.ARouter$$Interceptors),反射创建IInterceptorGroup实例
//并执行其IInterceptorGroup#loadInto方法
((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的话(文件名以com.alibaba.android.arouter.routes.ARouter$$Providers),反射创建IProviderGroup实例
//并执行其IProviderGroup#loadInto方法
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
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() + "]");
}
}
这个方法算是核心中的核心了。
其实也只做了两件事情
- 获取routerMap
- 遍历routerMap,反射并执行IRouteRoot#loadInto/IInterceptorGroup#loadInto/IProviderGroup#loadInto
ClassUtils#getFileNameByPackageName
public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
//记住,这里packageName的值是com.alibaba.android.arouter.routes
final Set<String> classNames = new HashSet<>();
//获取当前Apk目录下的所有dex文件
List<String> paths = getSourcePaths(context);
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
//遍历dex
for (final String path : paths) {
//使用线程池(默认核心线程数为CPU数+1,最大线程数CPU+1(也即是只有核心线程),等待队列ArrayBlockingQueue(容量64))
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
DexFile dexfile = null;
try {
//加载dex文件
if (path.endsWith(EXTRACTED_SUFFIX)) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
dexfile = new DexFile(path);
}
//找到所有的以com.alibaba.android.arouter.routes开头的文件
//也就是找到包com.alibaba.android.arouter.routes下所有的文件
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (Throwable ignore) {
Log.e("ARouter", "Scan map file in dex files made error.", ignore);
} finally {
if (null != dexfile) {
try {
dexfile.close();
} catch (Throwable ignore) {
}
}
parserCtl.countDown();
}
}
});
}
parserCtl.await();
Log.d(Consts.TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
return classNames;
}
总的来说,只干了一件事情,扫描所有的dex文件,找到com.alibaba.android.arouter.routes包下的所有文件并返回。这里的操作都是耗时操作。
但是com.alibaba.android.arouter.routes包下都是什么文件呢?
比如:
public class ARouter$$Root$$modulejava implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("m2", ARouter$$Group$$m2.class);
routes.put("module", ARouter$$Group$$module.class);
routes.put("test", ARouter$$Group$$test.class);
routes.put("yourservicegroupname", ARouter$$Group$$yourservicegroupname.class);
}
}
比如:
public class ARouter$$Interceptors$$modulejava implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(7, Test1Interceptor.class);
interceptors.put(90, TestInterceptor90.class);
}
}
比如:
public class ARouter$$Providers$$modulejava implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.alibaba.android.arouter.demo.service.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/yourservicegroupname/json", "yourservicegroupname", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.demo.module1.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/yourservicegroupname/single", "yourservicegroupname", null, -1, -2147483648));
}
}
比如:
public class ARouter$$Group$$test implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("ser", 9); put("ch", 5); put("fl", 6); put("dou", 7); put("boy", 0); put("url", 8); put("pac", 10); put("obj", 11); put("name", 8); put("objList", 11); put("map", 11); put("age", 3); put("height", 3); }}, -1, -2147483648));
atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new java.util.HashMap<String, Integer>(){{put("name", 8); put("boy", 0); put("age", 3); }}, -1, -2147483648));
atlas.put("/test/activity4", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/activity4", "test", null, -1, -2147483648));
atlas.put("/test/fragment", RouteMeta.build(RouteType.FRAGMENT, BlankFragment.class, "/test/fragment", "test", new java.util.HashMap<String, Integer>(){{put("ser", 9); put("pac", 10); put("ch", 5); put("obj", 11); put("fl", 6); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 11); put("map", 11); put("age", 3); put("height", 3); }}, -1, -2147483648));
atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class, "/test/webview", "test", null, -1, -2147483648));
}
}
这些都是APT生成的辅助类。
这个时候,我们停下来想一想,到现在为止,ARouter做了哪些事情?
①项目编译期,通过APT,生成辅助类(所有的辅助类包名都是com.alibaba.android.arouter.routes)
包括
- 接口IRouteRoot的实现类(比如ARouter$$Root$$modulejava.java)
- 接口IProviderGroup的实现类(比如ARouter$$Providers$$modulejava.java)
- 接口IInterceptorGroup的实现类(比如ARouter$$Interceptors$$modulejava.java)
- 接口IRouteGroup的实现类(比如ARouter$$Group$$test.java)
②ARouter#init初始化的时候,扫描dex文件,找到①生成的辅助类文件(也即是包com.alibaba.android.arouter.routes下的文件),放到routerMap中
③遍历routerMap,找到IRouteRoot/IProviderGroup/IInterceptorGroup的实现类,反射生成实例,并调用其loadInto方法
注意,这里没有实例化IRouteGroup,IRouteGroup的信息都在IRouteRoot中,这样做的目的是为了实现分组route的加载,用到了哪个group的route的信息,才会加载这个group的信息,没用到就不加载。这里可以仔细想想IProviderGroup/IInterceptorGroup/IRouteGroup的区别。
该方法执行完了以后,
- Warehouse#groupsIndex存放所有的IRouteGroup信息
- Warehouse#interceptorsIndex存放所有的IProvider信息
- Warehouse#providersIndex存放所有的IInterceptor信息
至此,就完成了初始化路由表的操作。
我们回过头来瞄一眼ARouter#init,里面初始化路由表以后,执行了_ARouter#afterInit
_ARouter#afterInit
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
这一句看着很熟悉。
- 跳转页面ARouter.getInstance().build("/test/activity").navigation();
- 获取其他组件接口HelloService helloService3 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation();
页面路由跳转/IProvider/拦截器都是ARouter.getInstance().build("/test/activity").navigation()这种形式的话,我们就先从拦截器interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();开始分析吧。
“/arouter/service/interceptor”
@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService{
//方法省略
}
public interface InterceptorService extends IProvider {
/**
* Do interceptions
*/
void doInterceptions(Postcard postcard, InterceptorCallback callback);
}
虽然这里我们是想看拦截器的实现,但是要明确一点:InterceptorServiceImpl是IProvider的实现类,获取InterceptorService也就是获取一个IProvider。有一点绕,简单来说,ARouter使用一个IProvider来实现拦截器的初始化。
后面的逻辑就变成了获取一个IProvider上了。
ARouter#build(java.lang.String)
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
_ARouter#build(java.lang.String)
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
//这里PathReplaceService的逻辑先跳过,后面再回头分析
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
//extractGroup:根据path获取group
//InterceptorService这里获取到的是"arouter"
return build(path, extractGroup(path), true);
}
}
_ARouter#build(java.lang.String, java.lang.String, java.lang.Boolean)
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的逻辑先跳过,后面再回头分析
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
}
return new Postcard(path, group);
}
}
也即是ARouter.getInstance().build("/arouter/service/interceptor").navigation()方法中,ARouter.getInstance().build("/arouter/service/interceptor")做的事情就是创建一个Postcard,其path是"/arouter/service/interceptor",group是"arouter".
Postcard#navigation()
public Object navigation() {
return navigation(null);
}
public Object navigation(Context context) {
return navigation(context, null);
}
public Object navigation(Context context, NavigationCallback callback) {
return ARouter.getInstance().navigation(context, this, -1, callback);
}
ARouter#navigation(Context, Postcard, int, NavigationCallback)
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}
_ARouter#navigation(Context, Postcard, int, NavigationCallback)
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//预处理
//执行时机早于拦截器
//这里,我们可以加log/拦截路由等
//默认为空
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
// Set context to postcard.
postcard.setContext(null == context ? mContext : context);
try {
//关键方法,待分析
//tips:实际做的事情是:去路由表中查找路由信息,如果是IProvider,就反射创建实例
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();
}
});
}
//看NoRouteFoundException也可以猜到,这里是没找到路由信息(比如path写错了,没匹配上)
//如果没找到路由信息
//执行回调
if (null != callback) {
//如果设置了callback
callback.onLost(postcard);
} else {
// No callback for this invoke, then we use the global degrade service.
//如果没设置callback,则执行全局的降级策略(暂时记住DegradeService,后面再分析)
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
//没找到路由信息的话,navigation方法就执行完了
return null;
}
//找到了路由信息,执行回调
if (null != callback) {
callback.onFound(postcard);
}
//判断是否需要执行拦截器逻辑
//这里只是一个Boolean变量标记值
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);
}
return null;
}
简单来说,这里做的事情有
- LogisticsCenter.completion(postcard):根据group和path查找路由信息
- 拦截器拦截
- _navigation(postcard, requestCode, callback)
LogisticsCenter#completion
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
//去Warehouse.routes中找,有没有创建过path对应的RouteMeta
//Warehouse.routes是HashMap,key是path,value是RouteMeta
if (null == routeMeta) {
//如果Warehouse.routes中没找到
//比如第一次加载的时候
// Maybe its does't exist, or didn't load.
if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
//如果找不到group信息,则抛出异常
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
//找到了group信息,则按照group加载
//比如我们获取InterceptorService,这里的group就是"arouter"
// 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()));
}
//加载group "arouter"
addRouteGroupDynamic(postcard.getGroup(), null);
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 {
//...暂时省略
}
}
//通过groupName去Warehouse.groupsIndex找对应的class
//反射创建class,并执行其loadInto方法
public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (Warehouse.groupsIndex.containsKey(groupName)){
// If this group is included, but it has not been loaded
// load this group first, because dynamic route has high priority.
Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(groupName);
}
//加载一次后就从group中移除
//从而保证只load一次
// cover old group.
if (null != group) {
group.loadInto(Warehouse.routes);
}
}
注意addRouteGroupDynamic(postcard.getGroup(), null)这个方法,通过groupName去groupIndex中查找,那"arouter"对应的是谁呢?正是ARouter$$Group$$arouter.class。
反射创建ARouter$$Group$$arouter对象,并执行ARouter$$Group$$arouter#loadInto方法
ARouter$$Root$$arouterapi和ARouter$$Group$$arouter
public class ARouter$$Root$$arouterapi implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("arouter", ARouter$$Group$$arouter.class);
}
}
public class ARouter$$Group$$arouter implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
//该方法只做了一件事情
//把AutowiredServiceImpl.class和InterceptorServiceImpl.class信息加载到Warehouse.routes中
//Warehouse.routes
atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER, AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, -1, -2147483648));
atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER, InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter", null, -1, -2147483648));
}
}
现在我们回过头来继续看LogisticsCenter#completion
public synchronized static void completion(Postcard postcard) {
//第一次加载,Warehouse.routes中找不到""/arouter/service/interceptor""
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// Maybe its does't exist, or didn't load.
if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
//那就执行ARouter$$Group$$arouter#loadInto
//执行完这个方法后,Warehouse.routes中就多了两个元素
//"/arouter/service/autowired" -> AutowiredServiceImpl.class
//"/arouter/service/interceptor" -> InterceptorServiceImpl.class
addRouteGroupDynamic(postcard.getGroup(), null);
//再执行一遍completion
completion(postcard); // Reload
}
} else {
//第二次加载的时候,Warehouse.routes中已经有了"/arouter/service/interceptor" -> InterceptorServiceImpl.class
//设置参数
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must implement IProvider
//如果是PROVIDER
//恰巧我们要找的InterceptorServiceImpl的类型就是PROVIDER
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
//找找Warehouse.providers中有没有已经初始化的实例
if (null == instance) { // There's no instance of this provider
//没初始化过就执行反射,完成初始化
//针对InterceptorServiceImpl.class来说,这里就是创建InterceptorServiceImpl实例,然后执行InterceptorServiceImpl#init方法
//再把初始化好的实例存到Warehouse.providers中
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
logger.error(TAG, "Init provider failed!", e);
throw new HandlerException("Init provider failed!");
}
}
postcard.setProvider(instance);
//跳过拦截器拦截,结合上面讲的ARouter#navigation(Context, Postcard, int, NavigationCallback)
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
//跳过拦截器拦截,结合上面讲的ARouter#navigation(Context, Postcard, int, NavigationCallback)
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
总结一下LogisticsCenter#completion方法做了啥:
- 去Warehouse.groupsIndex找到group对应的IRouteGroup,反射创建其实例,执行其IRouteGroup#loadInto方法,这样,就把group中的path->RouteMeta信息加载到Warehouse.routes中
- 从Warehouse.routes中找到path对应的RouteMeta信息(包括class类信息)
- 如果RouteMeta类型是PROVIDER,则反射创建其实例,执行其init方法,并把实例保存到Warehouse.providers中
以ARouter.getInstance().build("/arouter/service/interceptor").navigation()举例说明就是:
- Warehouse.groupsIndex找到group为"arouter"的IRouteGroup,这里找到的是ARouter$$Group$$arouter.class
- 反射ARouter$$Group$$arouter.class并执行其ARouter$$Group$$arouter#loadInto方法
- 把"/arouter/service/interceptor"->InterceptorServiceImpl.class信息加载到Warehouse.routes中
- 根据path="/arouter/service/interceptor"从Warehouse.routes中找到InterceptorServiceImpl.class
- 反射实例化InterceptorServiceImpl
- 执行InterceptorServiceImpl#init方法
InterceptorServiceImpl#init
public void init(final Context context) {
//线程池中执行
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
//遍历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中
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();
}
}
}
});
}
init方法做的事情很单一,就是一次性实例化全部的拦截器,存到 Warehouse.interceptors中。(想想为什么要这么做?)
这样,ARouter.getInstance().build("/arouter/service/interceptor").navigation()就分析完了,ARouter#init的时候,会创建所有的拦截器实例。ARouter.getInstance().build("/arouter/service/interceptor").navigation()方法返回的是InterceptorServiceImpl的实例。
另外,_ARouter#navigation(Context, Postcard, int, NavigationCallback)方法的最后,调用了_ARouter#_navigation
_ARouter#_navigation
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();
switch (postcard.getType()) {
case ACTIVITY:
//如果是ACTIVITY(页面跳转)
//就构建Intent
// Build intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (0 != flags) {
intent.setFlags(flags);
}
// Non activity, need FLAG_ACTIVITY_NEW_TASK
if (!(currentContext instanceof Activity)) {
intent.addFlags(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;
}
方法看着长,内容却很简单:
- 如果是页面跳转,就构建Intent,调系统的ActivityCompat.startActivityForResult方法
- 如果是PROVIDER,返回上一步LogisticsCenter.completion中已经创建好的实例
- 如果是BOARDCAST/CONTENT_PROVIDER/FRAGMENT,反射创建实例
这样,ARouter#init就分析完了,总结一下:
- 扫描所有的dex文件,找到包com.alibaba.android.arouter.routes下的全部文件(耗时操作)
- 如果是IRouteRoot/IInterceptorGroup/IProviderGroup,就反射创建实例,执行其loadInto方法,这样,以group为单位的路由表信息就被存放到Warehouse.groupsIndex/Warehouse.interceptorsIndex/Warehouse.providersIndex中
- 初始化拦截器(创建所有的拦截器实例,存到Warehouse.interceptors中)
另外使用ARouter.getInstance().build("path").navigation()方法获取IProvider的流程如下:
- 如果Warehouse.routes中已经有path对应的RouteMeta,则执行步骤3,如果没有(第一次初始化),则执行步骤2
- Warehouse.groupsIndex中查找group对应的类,实例化并执行loadInto方法,将RouteMeta信息加载到Warehouse.routes,然后重新执行步骤1
- 取出Warehouse.routes中path对应的RouteMeta,通过反射实例化class对象,并执行其init方法,实例存到Warehouse.providers中,并返回该实例对象
Activity跳转的流程如下:
- 同上
- 同上
- 取出Warehouse.routes中path对应的RouteMeta,创建Intent对象,调用ActivityCompat.startActivityForResult实现页面跳转
至此,我们回答了问题1/问题2和问题4.
下面我们来看下剩下的问题
问题3:拦截器是如何生效的?
我们可以看看_ARouter
private static InterceptorService interceptorService;
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//省略...
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
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());
}
});
}
//省略...
}
执行_ARouter#navigation的时候,执行了interceptorService.doInterceptions方法,前面我们已经知道,执行了interceptorService实际上是InterceptorServiceImpl。
InterceptorServiceImpl#doInterceptions
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);
//等待拦截器全部执行完,超时时间(默认300s)
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
//如果还有列表Warehouse.interceptors中拦截器没执行完
//报超时
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);
}
}
InterceptorServiceImpl#_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) {
// 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();
// Be attention, maybe the thread in callback has been changed,
// then the catch block(L207) will be invalid.
// The worst is the thread changed to main thread, then the app will be crash, if you throw this exception!
// if (!Looper.getMainLooper().equals(Looper.myLooper())) { // You shouldn't throw the exception if the thread is main thread.
// throw new HandlerException(exception.getMessage());
// }
}
});
}
}
这里一个一个调用拦截器,如果有拦截器拦截,就中断调用,否则,调用下一个拦截器进行拦截。
所以,拦截器总结如下
- ARouter#init时,反射创建全部拦截器实例,放到Warehouse.interceptors中
- Postcard#navigation()时,遍历Warehouse.interceptors调用各个拦截器拦截
最后,我们来看下最后一个问题。
问题5 ARouter的Gradle Plugin做了哪些优化?
该问题的关键是LogisticsCenter#loadRouterMap
LogisticsCenter#loadRouterMap
private static void loadRouterMap() {
registerByPlugin = false;
// auto generate register code by gradle plugin: arouter-auto-register
// looks like below:
// registerRouteRoot(new ARouter..Root..modulejava());
// registerRouteRoot(new ARouter..Root..modulekotlin());
}
private static void loadRouterMap() {
registerByPlugin = false;
// auto generate register code by gradle plugin: arouter-auto-register
// looks like below:
register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulekotlin");
register("com.alibaba.android.arouter.routes.ARouter$$Root$$arouterapi");
register("com.alibaba.android.arouter.routes.ARouter$$Interceptors$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulejava");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulekotlin");
register("com.alibaba.android.arouter.routes.ARouter$$Providers$$arouterapi");
}
上面的是gradle plugin修改之前的,下面的loadRouterMap是gradle plugin修改之后的。
private static void register(String className) {
if (!TextUtils.isEmpty(className)) {
try {
Class<?> clazz = Class.forName(className);
Object obj = clazz.getConstructor().newInstance();
if (obj instanceof IRouteRoot) {
registerRouteRoot((IRouteRoot) obj);
} else if (obj instanceof IProviderGroup) {
registerProvider((IProviderGroup) obj);
} else if (obj instanceof IInterceptorGroup) {
registerInterceptor((IInterceptorGroup) obj);
} else {
logger.info(TAG, "register failed, class name: " + className
+ " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
}
} catch (Exception e) {
logger.error(TAG,"register class error:" + className, e);
}
}
}
private static void registerRouteRoot(IRouteRoot routeRoot) {
markRegisteredByPlugin();
if (routeRoot != null) {
routeRoot.loadInto(Warehouse.groupsIndex);
}
}
private static void registerInterceptor(IInterceptorGroup interceptorGroup) {
markRegisteredByPlugin();
if (interceptorGroup != null) {
interceptorGroup.loadInto(Warehouse.interceptorsIndex);
}
}
private static void registerProvider(IProviderGroup providerGroup) {
markRegisteredByPlugin();
if (providerGroup != null) {
providerGroup.loadInto(Warehouse.providersIndex);
}
}
private static void markRegisteredByPlugin() {
if (!registerByPlugin) {
registerByPlugin = true;
}
}
瞄一眼register方法我们就能明白,这还是之前的那一套,跟不使用gradle plugin不同的地方在于,这里不需要扫描dex去找IRouteRoot/IInterceptorGroup/IProviderGroup,在编译期,gradle plugin就已经找到了这些,然后生成新的loadRouterMap方法。
网友评论