前置知識
APT
Annotation Processing Tool,自定義注解處理器庵芭。
搞Android的基本上都知道這個吧妹懒。許多第三方庫都使用了APT去實現(xiàn)自己的功能,比如butterknife双吆,比如X2C眨唬,比如我們要講的ARouter。
其基本做法是:
- 自定義編譯期注解(比如ARouter源碼中的arouter-annotation模塊)
- 自定義AbstractProcessor好乐,實現(xiàn)process方法匾竿,在該方法中掃描步驟1定義的注解,根據(jù)注解信息生成輔助文件(.java文件)(比如ARouter源碼中的arouter-cmpiler模塊)
- Runtime時期蔚万,通過反射創(chuàng)建輔助類(獲取步驟2生成的文件的全路徑岭妖,反射),調(diào)用輔助類中的方法(比如ARouter源碼中的arouter-api模塊)
自定義Gradle Plugin
一般是自定義gradle Transform + ASM反璃,實現(xiàn)AOP昵慌,可以在編譯期修改project和第三方依賴庫中的class文件(比如ARouter源碼中的arouter-gradle-plugin模塊),與APT主要是生成.java文件不同淮蜈,ASM操作的是.class文件斋攀。
自定義gradle Transform功能很強大,可以與ASM結(jié)合梧田,修改.class淳蔼,也可以操作資源文件(比如統(tǒng)一壓縮圖片,轉(zhuǎn)png大圖為webp等)裁眯。
至于ASM鹉梨,基于修改.class文件,我們即可以用ASM來插樁統(tǒng)計方法耗時穿稳,也可以用來實現(xiàn)自動化埋點存皂,甚至是修改第三方lib中的crash...
寫在前面
使用方法可以看ARouter。
帶著問題看源碼司草,這里主要的問題是:
- 初始化都做了什么艰垂?
- ARouter是如何實現(xiàn)組件間的路由跳轉(zhuǎn)的?
- 攔截器是如何生效的埋虹?
- IProvider 的實現(xiàn)機制
- ARouter的Gradle Plugin做了哪些優(yōu)化猜憎?
初始化
ARouter.init(getApplication());
ARouter的核心方法。
ARouter#init
public static void init(Application application) {
//如果沒初始化過搔课,就執(zhí)行初始化
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
//關(guān)鍵在這里胰柑,初始化路由表
hasInit = _ARouter.init(application);
if (hasInit) {
//加載好路由表以后,執(zhí)行其他操作
//這里是初始化攔截器
_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;
//創(chuàng)建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的關(guān)鍵爬泥,該方法默認空實現(xiàn)(不使用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)對應(yīng)
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)踩官,反射創(chuàng)建IRouteRoot實例
//并執(zhí)行其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),反射創(chuàng)建IInterceptorGroup實例
//并執(zhí)行其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)境输,反射創(chuàng)建IProviderGroup實例
//并執(zhí)行其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,反射并執(zhí)行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) {
//使用線程池(默認核心線程數(shù)為CPU數(shù)+1辩越,最大線程數(shù)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生成的輔助類欺旧。
這個時候姑丑,我們停下來想一想,到現(xiàn)在為止辞友,ARouter做了哪些事情栅哀?
①項目編譯期,通過APT称龙,生成輔助類(所有的輔助類包名都是com.alibaba.android.arouter.routes)
包括
- 接口IRouteRoot的實現(xiàn)類(比如ARouter$$Root$$modulejava.java)
- 接口IProviderGroup的實現(xiàn)類(比如ARouter$$Providers$$modulejava.java)
- 接口IInterceptorGroup的實現(xiàn)類(比如ARouter$$Interceptors$$modulejava.java)
- 接口IRouteGroup的實現(xiàn)類(比如ARouter$$Group$$test.java)
②ARouter#init初始化的時候留拾,掃描dex文件,找到①生成的輔助類文件(也即是包com.alibaba.android.arouter.routes下的文件)鲫尊,放到routerMap中
③遍歷routerMap痴柔,找到IRouteRoot/IProviderGroup/IInterceptorGroup的實現(xiàn)類,反射生成實例疫向,并調(diào)用其loadInto方法
注意咳蔚,這里沒有實例化IRouteGroup豪嚎,IRouteGroup的信息都在IRouteRoot中,這樣做的目的是為了實現(xiàn)分組route的加載谈火,用到了哪個group的route的信息侈询,才會加載這個group的信息,沒用到就不加載糯耍。這里可以仔細想想IProviderGroup/IInterceptorGroup/IRouteGroup的區(qū)別扔字。
該方法執(zhí)行完了以后,
- Warehouse#groupsIndex存放所有的IRouteGroup信息
- Warehouse#interceptorsIndex存放所有的IProvider信息
- Warehouse#providersIndex存放所有的IInterceptor信息
至此温技,就完成了初始化路由表的操作革为。
我們回過頭來瞄一眼ARouter#init,里面初始化路由表以后舵鳞,執(zhí)行了_ARouter#afterInit
_ARouter#afterInit
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
這一句看著很熟悉震檩。
- 跳轉(zhuǎn)頁面ARouter.getInstance().build("/test/activity").navigation();
- 獲取其他組件接口HelloService helloService3 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation();
頁面路由跳轉(zhuǎn)/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);
}
雖然這里我們是想看攔截器的實現(xiàn)恳蹲,但是要明確一點:InterceptorServiceImpl是IProvider的實現(xiàn)類,獲取InterceptorService也就是獲取一個IProvider俩滥。有一點繞嘉蕾,簡單來說,ARouter使用一個IProvider來實現(xiàn)攔截器的初始化霜旧。
后面的邏輯就變成了獲取一個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:根據(jù)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")做的事情就是創(chuàng)建一個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) {
//預(yù)處理
//執(zhí)行時機早于攔截器
//這里掷倔,我們可以加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 {
//關(guān)鍵方法,待分析
//tips:實際做的事情是:去路由表中查找路由信息个绍,如果是IProvider勒葱,就反射創(chuàng)建實例
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寫錯了巴柿,沒匹配上)
//如果沒找到路由信息
//執(zhí)行回調(diào)
if (null != callback) {
//如果設(shè)置了callback
callback.onLost(postcard);
} else {
// No callback for this invoke, then we use the global degrade service.
//如果沒設(shè)置callback凛虽,則執(zhí)行全局的降級策略(暫時記住DegradeService,后面再分析)
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
//沒找到路由信息的話广恢,navigation方法就執(zhí)行完了
return null;
}
//找到了路由信息凯旋,執(zhí)行回調(diào)
if (null != callback) {
callback.onFound(postcard);
}
//判斷是否需要執(zhí)行攔截器邏輯
//這里只是一個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):根據(jù)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中找,有沒有創(chuàng)建過path對應(yīng)的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找對應(yīng)的class
//反射創(chuàng)建class,并執(zhí)行其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"對應(yīng)的是誰呢夭苗?正是ARouter$$Group$$arouter.class信卡。
反射創(chuàng)建ARouter$$Group$$arouter對象,并執(zhí)行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));
}
}
現(xiàn)在我們回過頭來繼續(xù)看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 {
//那就執(zhí)行ARouter$$Group$$arouter#loadInto
//執(zhí)行完這個方法后傍菇,Warehouse.routes中就多了兩個元素
//"/arouter/service/autowired" -> AutowiredServiceImpl.class
//"/arouter/service/interceptor" -> InterceptorServiceImpl.class
addRouteGroupDynamic(postcard.getGroup(), null);
//再執(zhí)行一遍completion
completion(postcard); // Reload
}
} else {
//第二次加載的時候,Warehouse.routes中已經(jīng)有了"/arouter/service/interceptor" -> InterceptorServiceImpl.class
//設(shè)置參數(shù)
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中有沒有已經(jīng)初始化的實例
if (null == instance) { // There's no instance of this provider
//沒初始化過就執(zhí)行反射界赔,完成初始化
//針對InterceptorServiceImpl.class來說丢习,這里就是創(chuàng)建InterceptorServiceImpl實例,然后執(zhí)行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);
//跳過攔截器攔截淮悼,結(jié)合上面講的ARouter#navigation(Context, Postcard, int, NavigationCallback)
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
//跳過攔截器攔截咐低,結(jié)合上面講的ARouter#navigation(Context, Postcard, int, NavigationCallback)
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
總結(jié)一下LogisticsCenter#completion方法做了啥:
- 去Warehouse.groupsIndex找到group對應(yīng)的IRouteGroup,反射創(chuàng)建其實例袜腥,執(zhí)行其IRouteGroup#loadInto方法见擦,這樣,就把group中的path->RouteMeta信息加載到Warehouse.routes中
- 從Warehouse.routes中找到path對應(yīng)的RouteMeta信息(包括class類信息)
- 如果RouteMeta類型是PROVIDER羹令,則反射創(chuàng)建其實例鲤屡,執(zhí)行其init方法,并把實例保存到Warehouse.providers中
以ARouter.getInstance().build("/arouter/service/interceptor").navigation()舉例說明就是:
- Warehouse.groupsIndex找到group為"arouter"的IRouteGroup福侈,這里找到的是ARouter$$Group$$arouter.class
- 反射ARouter$$Group$$arouter.class并執(zhí)行其ARouter$$Group$$arouter#loadInto方法
- 把"/arouter/service/interceptor"->InterceptorServiceImpl.class信息加載到Warehouse.routes中
- 根據(jù)path="/arouter/service/interceptor"從Warehouse.routes中找到InterceptorServiceImpl.class
- 反射實例化InterceptorServiceImpl
- 執(zhí)行InterceptorServiceImpl#init方法
InterceptorServiceImpl#init
public void init(final Context context) {
//線程池中執(zhí)行
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 {
反射創(chuàng)建攔截器實例
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
//執(zhí)行攔截器的初始化方法
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的時候,會創(chuàng)建所有的攔截器實例衡奥。ARouter.getInstance().build("/arouter/service/interceptor").navigation()方法返回的是InterceptorServiceImpl的實例。
另外远荠,_ARouter#navigation(Context, Postcard, int, NavigationCallback)方法的最后矮固,調(diào)用了_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(頁面跳轉(zhuǎn))
//就構(gòu)建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:
//反射創(chuàng)建實例
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;
}
方法看著長,內(nèi)容卻很簡單:
- 如果是頁面跳轉(zhuǎn),就構(gòu)建Intent档址,調(diào)系統(tǒng)的ActivityCompat.startActivityForResult方法
- 如果是PROVIDER盹兢,返回上一步LogisticsCenter.completion中已經(jīng)創(chuàng)建好的實例
- 如果是BOARDCAST/CONTENT_PROVIDER/FRAGMENT,反射創(chuàng)建實例
這樣守伸,ARouter#init就分析完了绎秒,總結(jié)一下:
- 掃描所有的dex文件,找到包com.alibaba.android.arouter.routes下的全部文件(耗時操作)
- 如果是IRouteRoot/IInterceptorGroup/IProviderGroup尼摹,就反射創(chuàng)建實例见芹,執(zhí)行其loadInto方法,這樣蠢涝,以group為單位的路由表信息就被存放到Warehouse.groupsIndex/Warehouse.interceptorsIndex/Warehouse.providersIndex中
- 初始化攔截器(創(chuàng)建所有的攔截器實例玄呛,存到Warehouse.interceptors中)
另外使用ARouter.getInstance().build("path").navigation()方法獲取IProvider的流程如下:
- 如果Warehouse.routes中已經(jīng)有path對應(yīng)的RouteMeta,則執(zhí)行步驟3和二,如果沒有(第一次初始化)徘铝,則執(zhí)行步驟2
- Warehouse.groupsIndex中查找group對應(yīng)的類,實例化并執(zhí)行l(wèi)oadInto方法惯吕,將RouteMeta信息加載到Warehouse.routes惕它,然后重新執(zhí)行步驟1
- 取出Warehouse.routes中path對應(yīng)的RouteMeta,通過反射實例化class對象废登,并執(zhí)行其init方法淹魄,實例存到Warehouse.providers中,并返回該實例對象
Activity跳轉(zhuǎn)的流程如下:
- 同上
- 同上
- 取出Warehouse.routes中path對應(yīng)的RouteMeta堡距,創(chuàng)建Intent對象揭北,調(diào)用ActivityCompat.startActivityForResult實現(xiàn)頁面跳轉(zhuǎn)
至此,我們回答了問題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());
}
});
}
//省略...
}
執(zhí)行_ARouter#navigation的時候搔体,執(zhí)行了interceptorService.doInterceptions方法,前面我們已經(jīng)知道半醉,執(zhí)行了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);
//等待攔截器全部執(zhí)行完缩多,超時時間(默認300s)
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
//如果還有列表Warehouse.interceptors中攔截器沒執(zhí)行完
//報超時
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());
// }
}
});
}
}
這里一個一個調(diào)用攔截器呆奕,如果有攔截器攔截,就中斷調(diào)用衬吆,否則梁钾,調(diào)用下一個攔截器進行攔截。
所以逊抡,攔截器總結(jié)如下
- ARouter#init時姆泻,反射創(chuàng)建全部攔截器實例零酪,放到Warehouse.interceptors中
- Postcard#navigation()時,遍歷Warehouse.interceptors調(diào)用各個攔截器攔截
最后拇勃,我們來看下最后一個問題四苇。
問題5 ARouter的Gradle Plugin做了哪些優(yōu)化?
該問題的關(guān)鍵是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就已經(jīng)找到了這些妓肢,然后生成新的loadRouterMap方法。