前言
相信絕大多數(shù)公司項(xiàng)目都做了組件化。為了解耦,組件化勢(shì)必要解決組件間的通信。其中阿里巴巴開(kāi)源的Arouter很好的解決了組件間的通信,一直受到開(kāi)發(fā)者的青睞。今天,我們來(lái)一步步揭開(kāi)它的神秘面紗。
首先下載源代碼,項(xiàng)目地址:
https://github.com/alibaba/ARouter
來(lái)講一下項(xiàng)目結(jié)構(gòu)
源代碼
- app:項(xiàng)目主工程,演示代碼
- module-java:java演示代碼
- module-kotlin:kotlin演示代碼
- arouter-annotation:所有注解以及注解涉及到的類(lèi)
- arouter-compiler:注解處理器,APT
- arouter-gradle-plugin:路由表自動(dòng)注冊(cè)插件
- arouter-idea-plugin:路由跳轉(zhuǎn)插件,搜索ARouter Helper插件安裝即可。
- arouter-api:所有的api
第一步就是要生成注解類(lèi)
@Route @Autowired Interceptor Provider都會(huì)生成如下面所示的對(duì)應(yīng)注解類(lèi),java生成的注解類(lèi)的位置在build-generated-sourse-apt中,kotlin生成的注解類(lèi)的位置在build-generated-sourse-kapt
public class ARouter$$Group$$app implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/app/degrade1", RouteMeta.build(RouteType.PROVIDER, DegradeServiceImpl.class, "/app/degrade1", "app", null, -1, -2147483648));
atlas.put("/app/main", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/app/main", "app", null, -1, -2147483648));
atlas.put("/app/path", RouteMeta.build(RouteType.PROVIDER, PathReplaceServiceImpl.class, "/app/path", "app", null, -1, -2147483648));
}
}
這里需要重點(diǎn)關(guān)注一下RouteMeta這個(gè)類(lèi),這個(gè)類(lèi)存儲(chǔ)了目標(biāo)對(duì)象的所有信息。包括路由類(lèi)型、目標(biāo)對(duì)象類(lèi)、path、group、參數(shù)、優(yōu)先級(jí)、額外參數(shù)。
涉及到的知識(shí)點(diǎn):
- apt
- javapoet
- auto-service
這里是我寫(xiě)的一個(gè)AptDemo,僅供參考:
https://github.com/liulingfeng/APT
關(guān)于AbstractProcessor的process多次執(zhí)行可以通過(guò)下面方法處理
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
if (annotations != null && annotations.size() > 0) {
}
}
下面正式講解api
先整體感受一下整個(gè)流程
整體流程
根據(jù)官方說(shuō)明,首先在Application中調(diào)用如下api
if(BuildConfig.DEBUG){
ARouter.openLog();//打開(kāi)日志
ARouter.openDebug();//打開(kāi)路由調(diào)試
}
ARouter.init(this);
進(jìn)入Arouter.init(this)
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
}
}
hasInit保證只初始化一次,內(nèi)部調(diào)用了_ARouter.init(application),Arouter是門(mén)面, _Arouter是具體實(shí)現(xiàn),有一點(diǎn)裝飾模式的感覺(jué)。初始化之后調(diào)用 _ARouter.afterInit實(shí)例化攔截器(這個(gè)后面細(xì)講)。繼續(xù)跟進(jìn) _ARouter.init
protected static synchronized boolean init(Application application) {
mContext = application;
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
return true;
}
一眼就看到關(guān)鍵代碼在LogisticsCenter.init中,executor是一個(gè)自定義的線程池(實(shí)現(xiàn)了一種拋出錯(cuò)誤的方式)。
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
try {
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
Set<String> routerMap;
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
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);
} else {
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
代碼比較長(zhǎng),我把它分解一下
- 1.判斷是不是用插件自動(dòng)注冊(cè)路由表,插件注冊(cè)的方式另說(shuō)
- 2.從dex中加載指定路徑(com.alibaba.android.arouter.routes)下的所有類(lèi)名,其實(shí)就是注解生成類(lèi),然后根據(jù)版本號(hào)升級(jí)版本。非debuggable環(huán)境下從SharedPreferences緩存中讀取(做的一個(gè)優(yōu)化點(diǎn))
- 3.反射調(diào)用loadInto把Group、Interceptor、Provider的映射關(guān)系添加到集合中
看一下各種類(lèi)型的注解生成類(lèi)
Root(這里做了優(yōu)化先加載各個(gè)group,用到的時(shí)候再加載各個(gè)group下的路由)
public class ARouter$$Root$$app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("app", ARouter$$Group$$app.class);
}
}
Interceptor
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(9, TestInterceptor2.class);
interceptors.put(10, TestInterceptor.class);
}
}
Provider
public class ARouter$$Providers$$app implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.xls.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", null, -1, -2147483648));
}
}
init工作總結(jié)及知識(shí)點(diǎn)
- 1.把Group、Interceptor、Provider注解類(lèi)的映射添加到Warehouse.groupsIndex、Warehouse.interceptorsIndex、Warehouse.providersIndex集合中
- 2.實(shí)例化所有的Interceptor添加到Warehouse.interceptors中
- 3.dex分析-多dex怎么查找-熱修復(fù)的根本原理是什么
- 4.線程池-線程池各個(gè)參數(shù)-線程池拋出錯(cuò)誤的方法-如何保證線程池線程名字唯一性-原子類(lèi)
順便補(bǔ)充一下插件自動(dòng)注冊(cè)路由表
首先目光移到PluginLaunch,這是自定義插件的入口。
public class PluginLaunch implements Plugin<Project> {
@Override
public void apply(Project project) {
def android = project.extensions.getByType(AppExtension)
def transformImpl = new RegisterTransform(project)
ArrayList<ScanSetting> list = new ArrayList<>(3)
list.add(new ScanSetting('IRouteRoot'))
list.add(new ScanSetting('IInterceptorGroup'))
list.add(new ScanSetting('IProviderGroup'))
RegisterTransform.registerList = list
android.registerTransform(transformImpl)
}
}
}
這里完成了自定義Transform的注冊(cè)以及添加需要過(guò)濾的接口到ScanSetting,最主要的代碼自然是在RegisterTransform中。直奔RegisterTransform的transform方法,首先遍歷jar。
inputs.each { TransformInput input ->
input.jarInputs.each {
if (ScanUtil.shouldProcessPreDexJar(src.absolutePath)) {
ScanUtil.scanJar(src, dest)
}
FileUtils.copyFile(src, dest)
}
static void scanJar(File jarFile, File destFile) {
if (jarFile) {
def file = new JarFile(jarFile)
Enumeration enumeration = file.entries()
while (enumeration.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) enumeration.nextElement()
String entryName = jarEntry.getName()
if (entryName.startsWith("com/alibaba/android/arouter/routes/")) {
InputStream inputStream = file.getInputStream(jarEntry)
scanClass(inputStream)
inputStream.close()
} else if ("com/alibaba/android/arouter/core/LogisticsCenter.class" == entryName) {
RegisterTransform.fileContainsInitClass = destFile
}
}
file.close()
}
}
做到兩步工作:1.把com/alibaba/android/arouter/routes包名下的交給scanClass處理(這個(gè)稍后會(huì)分析到) 2.找到LogisticsCenter.class類(lèi),對(duì)于這個(gè)類(lèi)想必很熟悉吧。
接下來(lái)遍歷directory
input.directoryInputs.each { DirectoryInput directoryInput ->
directoryInput.file.eachFileRecurse { File file ->
if(file.isFile() && ScanUtil.shouldProcessClass(path)){
ScanUtil.scanClass(file)
}
}
}
static void scanClass(InputStream inputStream) {
ClassReader cr = new ClassReader(inputStream)
ClassWriter cw = new ClassWriter(cr, 0)
ScanClassVisitor cv = new ScanClassVisitor(Opcodes.ASM5, cw)
cr.accept(cv, ClassReader.EXPAND_FRAMES)
inputStream.close()
}
把文件流丟給ScanClassVisitor
static class ScanClassVisitor extends ClassVisitor {
ScanClassVisitor(int api, ClassVisitor cv) {
super(api, cv)
}
void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces)
RegisterTransform.registerList.each { ext ->
if (ext.interfaceName && interfaces != null) {
interfaces.each { itName ->
if (itName == ext.interfaceName) {
ext.classList.add(name)
}
}
}
}
}
}
一看就明白,就是把所有實(shí)現(xiàn)了IRouteRoot、IInterceptorGroup、IProviderGroup接口的類(lèi)存到集合中。
接著看最后一步做了什么
if (fileContainsInitClass) {
registerList.each { ext ->
if (ext.classList.isEmpty()) {
Logger.e("No class implements found for interface:" + ext.interfaceName)
} else {
RegisterCodeGenerator.insertInitCodeTo(ext)
}
}
}
關(guān)鍵代碼都在RegisterCodeGenerator這個(gè)類(lèi)中,我只列關(guān)鍵代碼。
private byte[] referHackWhenInit(InputStream inputStream) {
ClassReader cr = new ClassReader(inputStream)
ClassWriter cw = new ClassWriter(cr, 0)
ClassVisitor cv = new MyClassVisitor(Opcodes.ASM5, cw)
cr.accept(cv, ClassReader.EXPAND_FRAMES)
return cw.toByteArray()
}
MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions)
if (name == "loadRouterMap") {
mv = new RouteMethodVisitor(Opcodes.ASM5, mv)
}
return mv
}
找到hook點(diǎn)loadRouterMap。hook點(diǎn)的設(shè)計(jì)特別巧妙,增強(qiáng)了代碼的可讀性。
void visitInsn(int opcode) {
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) {
extension.classList.each { name ->
mv.visitMethodInsn(Opcodes.INVOKESTATIC
, "com/alibaba/android/arouter/core/LogisticsCenter"
, "register"
, "(Ljava/lang/String;)V"
, false)
}
}
super.visitInsn(opcode)
}
調(diào)用LogisticsCenter的register方法,我們來(lái)看一下register方法做了什么。
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);
}
}
}
所有實(shí)現(xiàn)了IRouteRoot、IInterceptorGroup、IProviderGroup接口的類(lèi)都加入了Warehouse相對(duì)應(yīng)的集合中。至此自動(dòng)注冊(cè)工作完成。
路由跳轉(zhuǎn)
ARouter.getInstance().build("/home/test").withString("key3", "888")
.withLong("key1", 666L)
.navigation(this)
先看build,new一個(gè)Postcard對(duì)象并給Postcard設(shè)置path和group。Postcard構(gòu)造方法中new了一個(gè)bundler對(duì)象。PathReplaceService提供了動(dòng)態(tài)改path的方式,后面細(xì)講。
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);
}
}
.withString("key3", "888").withLong("key1", 666L)把參數(shù)設(shè)置給當(dāng)前Postcard的bundle中。
再看navigation方法
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
if (debuggable()) {
Toast.makeText(mContext, "There's no route matched!\n" +
" Path = [" + postcard.getPath() + "]\n" +
" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
}
if (null != callback) {
callback.onLost(postcard);
} else {
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
return null;
}
先看第一部分,重點(diǎn)落在LogisticsCenter.completion(postcard)。內(nèi)部主要做的是實(shí)例化當(dāng)前group下的具體Route添加到Warehouse.routes,如果沒(méi)找到就降級(jí)處理,兩種方式(1.設(shè)置NavigationCallback 2.實(shí)現(xiàn)DegradeService)
public synchronized static void completion(Postcard postcard) {
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
try {
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
completion(postcard);
}
} else {
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
if (null != rawUri) {
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
switch (routeMeta.getType()) {
case PROVIDER:
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) {
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
postcard.setProvider(instance);
postcard.greenChannel();
break;
case FRAGMENT:
postcard.greenChannel();
default:
break;
}
}
}
分析一下這段代碼
- 1.判斷Warehouse的routes中對(duì)應(yīng)path的RouteMeta是否為空,看過(guò)注解生成類(lèi)其實(shí)我們知道RouteMeta保存了類(lèi)的具體信息
- 2.在集合中找到對(duì)應(yīng)的group分組,然后實(shí)例化對(duì)應(yīng)分組下的具體Route添加到集合中
- 3.把RouteMeta的各種信息設(shè)置給當(dāng)前postcard對(duì)象
- 4.uri跳轉(zhuǎn)的處理,uri跳轉(zhuǎn)和普通跳轉(zhuǎn)唯一的區(qū)別就是參數(shù)的剝離,普通跳轉(zhuǎn)是直接設(shè)置的而uri是通過(guò)在鏈接中剝離的,其中參數(shù)的數(shù)據(jù)類(lèi)型是在Routemeta的paramsType中設(shè)置的
- 5.根據(jù)跳轉(zhuǎn)的類(lèi)型不同做不同處理。如果是服務(wù),直接實(shí)例化當(dāng)前服務(wù)調(diào)用init方法并設(shè)置給postcard。設(shè)置綠色通道;如果是fragment,設(shè)置綠色通道。所謂綠色通道就是不被攔截器攔截。
第二個(gè)部分是處理攔截。我們稍后再講
先看第三部分
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
case ACTIVITY:
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
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;
}
看到這里是不是很親切,這不就是我們平時(shí)常寫(xiě)的startActivity(intent,class)嗎?如果是fragment的話反射調(diào)用Fragment構(gòu)造方法返回fragment對(duì)象。provider也是返回 Provider對(duì)象。至此跳轉(zhuǎn)這一塊基本上都搞清楚了。
分析一下攔截器怎么實(shí)現(xiàn)的
之前講了Aroute.init之后會(huì)將所有的攔截器實(shí)例化。我們看看_ARouter.afterInit()做了什么
static void afterInit() {
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
使用自己的路由方法初始化interceptorService服務(wù),沒(méi)毛病。該服務(wù)的實(shí)現(xiàn)類(lèi)是InterceptorServiceImpl,從前面的分析可以知道navigation會(huì)調(diào)用服務(wù)的init方法。看看init里面做了什么
@Override
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;
}
}
});
}
反射調(diào)用所有攔截器的構(gòu)造函數(shù)實(shí)例化對(duì)象添加到Warehouse.interceptors并調(diào)用init方法,這里使用了object.wait和object.notifyAll保證子線程中的所有攔截器實(shí)例化完成。攔截的時(shí)機(jī)在前面已經(jīng)提到過(guò)了,我們來(lái)看看具體的代碼。
if (!postcard.isGreenChannel()) {
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
_excute(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(new HandlerException(postcard.getTag().toString()));
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
private static void _excute(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();
_excute(index + 1, counter, postcard);
}
@Override
public void onInterrupt(Throwable exception) {
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
counter.cancel();
}
});
}
}
使用CountDownLatch.await使得代碼阻塞直到所有攔截器執(zhí)行完成或者超時(shí)。攔截器process方法中需要調(diào)用callback.onContinue才能調(diào)用到counter.countDown()移交到下一個(gè)攔截器,這就解釋了自定義的攔截器為什么一定要調(diào)用counter.countDown()
涉及知識(shí)點(diǎn)
- 1.線程間通信
- 2.CountDownLatch
- 3.Object.wait/Object.notify
降級(jí)處理
兩種方式:1.navigation的時(shí)候添加NavigationCallback回調(diào) 2.寫(xiě)一個(gè)類(lèi)實(shí)現(xiàn)DegradeService別忘了添加@Route path可以隨意 第一種比較簡(jiǎn)單我么不講,講一下第二種方式
@Route(path = "/app/degrade1")
class DegradeServiceImpl : DegradeService {
override fun onLost(context: Context?, postcard: Postcard?) {
Log.e("降級(jí)處理","自定義降級(jí)處理")
}
override fun init(context: Context?) {
}
}
生成的注解類(lèi)在ARouter$$Providers$$app中,也是init的時(shí)候就把映射關(guān)系添加到集合中。調(diào)用的地方是在navigation中,這段代碼也間接的說(shuō)明了NavigationCallback的優(yōu)先級(jí)高于全局降級(jí)處理。
if (null != callback) {
callback.onLost(postcard);
} else {
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
關(guān)鍵代碼是下面一段代碼,詮釋了服務(wù)的navigation是如何運(yùn)行的
protected <T> T navigation(Class<? extends T> service) {
try {
Postcard postcard = LogisticsCenter.buildProvider(service.getName());
if (null == postcard) {
postcard = LogisticsCenter.buildProvider(service.getSimpleName());
}
LogisticsCenter.completion(postcard);
return (T) postcard.getProvider();
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
return null;
}
}
buildProvider是根據(jù)service的名字從集合中找到對(duì)應(yīng)的RouteMeta并把path和group設(shè)置給postcard,接下來(lái)也是給postcard設(shè)置其他各種參數(shù),和上面分析的大同小異。
path動(dòng)態(tài)改變
調(diào)用的方式和降級(jí)處理一模一樣,時(shí)機(jī)是在build的時(shí)候。
參數(shù)自動(dòng)獲取
@Autowired
@JvmField
var key3: String? = null
@Autowired
@JvmField
var key1: Long = 0L
ARouter.getInstance().inject(this)
從文檔中可以知道,按照上面的方式就可以自動(dòng)獲取各個(gè)參數(shù)。關(guān)鍵代碼肯定是在inject方法中,調(diào)用的還是服務(wù)。
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
autowiredService.autowire(thiz);
}
}
看看AutowiredService的autowire方法
@Override
public void autowire(Object instance) {
String className = instance.getClass().getName();
try {
if (!blackList.contains(className)) {
ISyringe autowiredHelper = classCache.get(className);
if (null == autowiredHelper) {
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
autowiredHelper.inject(instance);
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
blackList.add(className);
}
}
最關(guān)鍵的方法是XXclass_$$ARouter$$Autowired.inject,其實(shí)這個(gè)類(lèi)還是在注解生成類(lèi)中
public class TestOneActivity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
TestOneActivity substitute = (TestOneActivity)target;
substitute.key3 = substitute.getIntent().getStringExtra("girl");
substitute.key1 = substitute.getIntent().getLongExtra("key1", substitute.key1);
}
}
還是通過(guò)getIntent().getExtra方法獲取的參數(shù),然后把獲取的參數(shù)設(shè)置給當(dāng)前類(lèi)。
分析完源碼之后捫心自問(wèn)一下下面問(wèn)題是否能回答上來(lái)
個(gè)人的一些思考,大家可以討論一下
(正文已結(jié)束)
推薦閱讀:adobe軟件列表
免責(zé)聲明及提醒:此文內(nèi)容為本網(wǎng)所轉(zhuǎn)載企業(yè)宣傳資訊,該相關(guān)信息僅為宣傳及傳遞更多信息之目的,不代表本網(wǎng)站觀點(diǎn),文章真實(shí)性請(qǐng)瀏覽者慎重核實(shí)!任何投資加盟均有風(fēng)險(xiǎn),提醒廣大民眾投資需謹(jǐn)慎!