国产午夜男女在线|欧美日本一道高清国产|亚洲日韩乱码中文字幕|麻豆国产97在线精品一区|日韩一区2区三区另类图片|亚洲精品国产99在线观看|亚洲国产午夜福利精品大秀在线|一级做a爰片性色毛片免费网站

          1. <form id="n2a4a"><nav id="n2a4a"></nav></form>
          2. 您當(dāng)前的位置 :寧夏資訊網(wǎng) > 資訊 >  內(nèi)容正文
            投稿

            全網(wǎng)最全面的Arouter源碼解析

            寧夏資訊網(wǎng) 2020-03-30 06:05:02 來源: 閱讀:-

            前言

            相信絕大多數(shù)公司項(xiàng)目都做了組件化。為了解耦,組件化勢必要解決組件間的通信。其中阿里巴巴開源的Arouter很好的解決了組件間的通信,一直受到開發(fā)者的青睞。今天,我們來一步步揭開它的神秘面紗。

            首先下載源代碼,項(xiàng)目地址:

            https://github.com/alibaba/ARouter

            來講一下項(xiàng)目結(jié)構(gòu)

            源代碼

            • app:項(xiàng)目主工程,演示代碼
            • module-java:java演示代碼
            • module-kotlin:kotlin演示代碼
            • arouter-annotation:所有注解以及注解涉及到的類
            • arouter-compiler:注解處理器,APT
            • arouter-gradle-plugin:路由表自動注冊插件
            • arouter-idea-plugin:路由跳轉(zhuǎn)插件,搜索ARouter Helper插件安裝即可。
            • arouter-api:所有的api

            第一步就是要生成注解類

            @Route @Autowired Interceptor Provider都會生成如下面所示的對應(yīng)注解類,java生成的注解類的位置在build-generated-sourse-apt中,kotlin生成的注解類的位置在build-generated-sourse-kapt

            public class ARouter$$Group$$app implements IRouteGroup {
            @Override
            public void loadInto(Map&lt;String, RouteMeta&gt; atlas) {
            atlas.put(&#34;/app/degrade1&#34;, RouteMeta.build(RouteType.PROVIDER, DegradeServiceImpl.class, &#34;/app/degrade1&#34;, &#34;app&#34;, null, -1, -2147483648));
            atlas.put(&#34;/app/main&#34;, RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, &#34;/app/main&#34;, &#34;app&#34;, null, -1, -2147483648));
            atlas.put(&#34;/app/path&#34;, RouteMeta.build(RouteType.PROVIDER, PathReplaceServiceImpl.class, &#34;/app/path&#34;, &#34;app&#34;, null, -1, -2147483648));
            }
            }

            這里需要重點(diǎn)關(guān)注一下RouteMeta這個類,這個類存儲了目標(biāo)對象的所有信息。包括路由類型、目標(biāo)對象類、path、group、參數(shù)、優(yōu)先級、額外參數(shù)。

            涉及到的知識點(diǎn):

            1. apt
            2. javapoet
            3. auto-service

            這里是我寫的一個AptDemo,僅供參考:

            https://github.com/liulingfeng/APT

            關(guān)于AbstractProcessor的process多次執(zhí)行可以通過下面方法處理

            @Override
            public boolean process(Set&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnvironment) {
            if (annotations != null &amp;&amp; annotations.size() &gt; 0) {

            }
            }

            下面正式講解api

            先整體感受一下整個流程

            整體流程

            根據(jù)官方說明,首先在Application中調(diào)用如下api

            if(BuildConfig.DEBUG){
            ARouter.openLog();//打開日志
            ARouter.openDebug();//打開路由調(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是門面, _Arouter是具體實(shí)現(xiàn),有一點(diǎn)裝飾模式的感覺。初始化之后調(diào)用 _ARouter.afterInit實(shí)例化攔截器(這個后面細(xì)講)。繼續(xù)跟進(jìn) _ARouter.init

            protected static synchronized boolean init(Application application) {
            mContext = application;
            LogisticsCenter.init(mContext, executor);
            logger.info(Consts.TAG, &#34;ARouter init success!&#34;);
            hasInit = true;
            return true;
            }

            一眼就看到關(guān)鍵代碼在LogisticsCenter.init中,executor是一個自定義的線程池(實(shí)現(xiàn)了一種拋出錯誤的方式)。

            public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            try {
            if (registerByPlugin) {
            logger.info(TAG, &#34;Load router map by arouter-auto-register plugin.&#34;);
            } else {
            Set&lt;String&gt; 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 + &#34;ARouter init logistics center exception! [&#34; + e.getMessage() + &#34;]&#34;);
            }
            }

            代碼比較長,我把它分解一下

            • 1.判斷是不是用插件自動注冊路由表,插件注冊的方式另說
            • 2.從dex中加載指定路徑(com.alibaba.android.arouter.routes)下的所有類名,其實(shí)就是注解生成類,然后根據(jù)版本號升級版本。非debuggable環(huán)境下從SharedPreferences緩存中讀取(做的一個優(yōu)化點(diǎn))
            • 3.反射調(diào)用loadInto把Group、Interceptor、Provider的映射關(guān)系添加到集合中

            看一下各種類型的注解生成類
            Root(這里做了優(yōu)化先加載各個group,用到的時(shí)候再加載各個group下的路由)

            public class ARouter$$Root$$app implements IRouteRoot {
            @Override
            public void loadInto(Map&lt;String, Class&lt;? extends IRouteGroup&gt;&gt; routes) {
            routes.put(&#34;app&#34;, ARouter$$Group$$app.class);
            }
            }

            Interceptor

            public class ARouter$$Interceptors$$app implements IInterceptorGroup {
            @Override
            public void loadInto(Map&lt;Integer, Class&lt;? extends IInterceptor&gt;&gt; interceptors) {
            interceptors.put(9, TestInterceptor2.class);
            interceptors.put(10, TestInterceptor.class);
            }
            }

            Provider

            public class ARouter$$Providers$$app implements IProviderGroup {
            @Override
            public void loadInto(Map&lt;String, RouteMeta&gt; providers) {
            providers.put(&#34;com.xls.HelloService&#34;, RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, &#34;/yourservicegroupname/hello&#34;, &#34;yourservicegroupname&#34;, null, -1, -2147483648));
            }
            }

            init工作總結(jié)及知識點(diǎn)

            • 1.把Group、Interceptor、Provider注解類的映射添加到Warehouse.groupsIndex、Warehouse.interceptorsIndex、Warehouse.providersIndex集合中
            • 2.實(shí)例化所有的Interceptor添加到Warehouse.interceptors中
            • 3.dex分析-多dex怎么查找-熱修復(fù)的根本原理是什么
            • 4.線程池-線程池各個參數(shù)-線程池拋出錯誤的方法-如何保證線程池線程名字唯一性-原子類

            順便補(bǔ)充一下插件自動注冊路由表

            首先目光移到PluginLaunch,這是自定義插件的入口。

            public class PluginLaunch implements Plugin&lt;Project&gt; {
            @Override
            public void apply(Project project) {
            def android = project.extensions.getByType(AppExtension)
            def transformImpl = new RegisterTransform(project)

            ArrayList&lt;ScanSetting&gt; list = new ArrayList&lt;&gt;(3)
            list.add(new ScanSetting(&#39;IRouteRoot&#39;))
            list.add(new ScanSetting(&#39;IInterceptorGroup&#39;))
            list.add(new ScanSetting(&#39;IProviderGroup&#39;))
            RegisterTransform.registerList = list
            android.registerTransform(transformImpl)
            }
            }
            }

            這里完成了自定義Transform的注冊以及添加需要過濾的接口到ScanSetting,最主要的代碼自然是在RegisterTransform中。直奔RegisterTransform的transform方法,首先遍歷jar。

            inputs.each { TransformInput input -&gt;
            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(&#34;com/alibaba/android/arouter/routes/&#34;)) {
            InputStream inputStream = file.getInputStream(jarEntry)
            scanClass(inputStream)
            inputStream.close()
            } else if (&#34;com/alibaba/android/arouter/core/LogisticsCenter.class&#34; == entryName) {
            RegisterTransform.fileContainsInitClass = destFile
            }
            }
            file.close()
            }
            }

            做到兩步工作:1.把com/alibaba/android/arouter/routes包名下的交給scanClass處理(這個稍后會分析到) 2.找到LogisticsCenter.class類,對于這個類想必很熟悉吧。

            接下來遍歷directory

            input.directoryInputs.each { DirectoryInput directoryInput -&gt;
            directoryInput.file.eachFileRecurse { File file -&gt;
            if(file.isFile() &amp;&amp; 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 -&gt;
            if (ext.interfaceName &amp;&amp; interfaces != null) {
            interfaces.each { itName -&gt;
            if (itName == ext.interfaceName) {
            ext.classList.add(name)
            }
            }
            }
            }
            }
            }

            一看就明白,就是把所有實(shí)現(xiàn)了IRouteRoot、IInterceptorGroup、IProviderGroup接口的類存到集合中。

            接著看最后一步做了什么

            if (fileContainsInitClass) {
            registerList.each { ext -&gt;
            if (ext.classList.isEmpty()) {
            Logger.e(&#34;No class implements found for interface:&#34; + ext.interfaceName)
            } else {
            RegisterCodeGenerator.insertInitCodeTo(ext)
            }
            }
            }

            關(guān)鍵代碼都在RegisterCodeGenerator這個類中,我只列關(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 == &#34;loadRouterMap&#34;) {
            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 &gt;= Opcodes.IRETURN &amp;&amp; opcode &lt;= Opcodes.RETURN)) {
            extension.classList.each { name -&gt;
            mv.visitMethodInsn(Opcodes.INVOKESTATIC
            , &#34;com/alibaba/android/arouter/core/LogisticsCenter&#34;
            , &#34;register&#34;
            , &#34;(Ljava/lang/String;)V&#34;
            , false)
            }
            }
            super.visitInsn(opcode)
            }

            調(diào)用LogisticsCenter的register方法,我們來看一下register方法做了什么。

             private static void register(String className) {
            if (!TextUtils.isEmpty(className)) {
            try {
            Class&lt;?&gt; 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, &#34;register failed, class name: &#34; + className
            + &#34; should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.&#34;);
            }
            } catch (Exception e) {
            logger.error(TAG,&#34;register class error:&#34; + className);
            }
            }
            }

            所有實(shí)現(xiàn)了IRouteRoot、IInterceptorGroup、IProviderGroup接口的類都加入了Warehouse相對應(yīng)的集合中。至此自動注冊工作完成。

            路由跳轉(zhuǎn)

            ARouter.getInstance().build(&#34;/home/test&#34;).withString(&#34;key3&#34;, &#34;888&#34;)
            .withLong(&#34;key1&#34;, 666L)
            .navigation(this)

            先看build,new一個Postcard對象并給Postcard設(shè)置path和group。Postcard構(gòu)造方法中new了一個bundler對象。PathReplaceService提供了動態(tài)改path的方式,后面細(xì)講。

            protected Postcard build(String path, String group) {
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
            throw new HandlerException(Consts.TAG + &#34;Parameter is invalid!&#34;);
            } else {
            PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
            if (null != pService) {
            path = pService.forString(path);
            }
            return new Postcard(path, group);
            }
            }

            .withString(&#34;key3&#34;, &#34;888&#34;).withLong(&#34;key1&#34;, 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, &#34;There&#39;s no route matched!\n&#34; +
            &#34; Path = [&#34; + postcard.getPath() + &#34;]\n&#34; +
            &#34; Group = [&#34; + postcard.getGroup() + &#34;]&#34;, 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,如果沒找到就降級處理,兩種方式(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&lt;? extends IRouteGroup&gt; groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
            if (null == groupMeta) {
            throw new NoRouteFoundException(TAG + &#34;There is no route match the path [&#34; + postcard.getPath() + &#34;], in group [&#34; + postcard.getGroup() + &#34;]&#34;);
            } else {
            try {
            IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
            iGroupInstance.loadInto(Warehouse.routes);
            Warehouse.groupsIndex.remove(postcard.getGroup());
            } catch (Exception e) {
            throw new HandlerException(TAG + &#34;Fatal exception when loading group meta. [&#34; + e.getMessage() + &#34;]&#34;);
            }
            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&lt;String, String&gt; resultMap = TextUtils.splitQueryParameters(rawUri);
            Map&lt;String, Integer&gt; paramsType = routeMeta.getParamsType();

            if (MapUtils.isNotEmpty(paramsType)) {
            for (Map.Entry&lt;String, Integer&gt; 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&lt;? extends IProvider&gt; providerMeta = (Class&lt;? extends IProvider&gt;) 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(&#34;Init provider failed! &#34; + e.getMessage());
            }
            }
            postcard.setProvider(instance);
            postcard.greenChannel();
            break;
            case FRAGMENT:
            postcard.greenChannel();
            default:
            break;
            }
            }
            }

            分析一下這段代碼

            • 1.判斷Warehouse的routes中對應(yīng)path的RouteMeta是否為空,看過注解生成類其實(shí)我們知道RouteMeta保存了類的具體信息
            • 2.在集合中找到對應(yīng)的group分組,然后實(shí)例化對應(yīng)分組下的具體Route添加到集合中
            • 3.把RouteMeta的各種信息設(shè)置給當(dāng)前postcard對象
            • 4.uri跳轉(zhuǎn)的處理,uri跳轉(zhuǎn)和普通跳轉(zhuǎn)唯一的區(qū)別就是參數(shù)的剝離,普通跳轉(zhuǎn)是直接設(shè)置的而uri是通過在鏈接中剝離的,其中參數(shù)的數(shù)據(jù)類型是在Routemeta的paramsType中設(shè)置的
            • 5.根據(jù)跳轉(zhuǎn)的類型不同做不同處理。如果是服務(wù),直接實(shí)例化當(dāng)前服務(wù)調(diào)用init方法并設(shè)置給postcard。設(shè)置綠色通道;如果是fragment,設(shè)置綠色通道。所謂綠色通道就是不被攔截器攔截。

            第二個部分是處理攔截。我們稍后再講
            先看第三部分

            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, &#34;Fetch fragment instance error, &#34; + TextUtils.formatStackTrace(ex.getStackTrace()));
            }
            case METHOD:
            case SERVICE:
            default:
            return null;
            }

            return null;
            }

            看到這里是不是很親切,這不就是我們平時(shí)常寫的startActivity(intent,class)嗎?如果是fragment的話反射調(diào)用Fragment構(gòu)造方法返回fragment對象。provider也是返回 Provider對象。至此跳轉(zhuǎn)這一塊基本上都搞清楚了。

            分析一下攔截器怎么實(shí)現(xiàn)的

            之前講了Aroute.init之后會將所有的攔截器實(shí)例化。我們看看_ARouter.afterInit()做了什么

            static void afterInit() {
            interceptorService = (InterceptorService) ARouter.getInstance().build(&#34;/arouter/service/interceptor&#34;).navigation();
            }

            使用自己的路由方法初始化interceptorService服務(wù),沒毛病。該服務(wù)的實(shí)現(xiàn)類是InterceptorServiceImpl,從前面的分析可以知道navigation會調(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&lt;Integer, Class&lt;? extends IInterceptor&gt;&gt; entry : Warehouse.interceptorsIndex.entrySet()) {
            Class&lt;? extends IInterceptor&gt; interceptorClass = entry.getValue();
            try {
            IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
            iInterceptor.init(context);
            Warehouse.interceptors.add(iInterceptor);
            } catch (Exception ex) {
            throw new HandlerException(TAG + &#34;ARouter init interceptor error! name = [&#34; + interceptorClass.getName() + &#34;], reason = [&#34; + ex.getMessage() + &#34;]&#34;);
            }
            }

            interceptorHasInit = true;
            }
            }
            });
            }

            反射調(diào)用所有攔截器的構(gòu)造函數(shù)實(shí)例化對象添加到Warehouse.interceptors并調(diào)用init方法,這里使用了object.wait和object.notifyAll保證子線程中的所有攔截器實(shí)例化完成。攔截的時(shí)機(jī)在前面已經(jīng)提到過了,我們來看看具體的代碼。

            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 &amp;&amp; Warehouse.interceptors.size() &gt; 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() &gt; 0) {
            callback.onInterrupt(new HandlerException(&#34;The interceptor processing timed out.&#34;));
            } 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 &lt; 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(&#34;No message.&#34;) : exception.getMessage()); // save the exception message for backup.
            counter.cancel();
            }
            });
            }
            }

            使用CountDownLatch.await使得代碼阻塞直到所有攔截器執(zhí)行完成或者超時(shí)。攔截器process方法中需要調(diào)用callback.onContinue才能調(diào)用到counter.countDown()移交到下一個攔截器,這就解釋了自定義的攔截器為什么一定要調(diào)用counter.countDown()

            涉及知識點(diǎn)

            • 1.線程間通信
            • 2.CountDownLatch
            • 3.Object.wait/Object.notify

            降級處理

            兩種方式:1.navigation的時(shí)候添加NavigationCallback回調(diào) 2.寫一個類實(shí)現(xiàn)DegradeService別忘了添加@Route path可以隨意 第一種比較簡單我么不講,講一下第二種方式

            @Route(path = &#34;/app/degrade1&#34;)
            class DegradeServiceImpl : DegradeService {
            override fun onLost(context: Context?, postcard: Postcard?) {
            Log.e(&#34;降級處理&#34;,&#34;自定義降級處理&#34;)
            }

            override fun init(context: Context?) {
            }
            }

            生成的注解類在ARouter$$Providers$$app中,也是init的時(shí)候就把映射關(guān)系添加到集合中。調(diào)用的地方是在navigation中,這段代碼也間接的說明了NavigationCallback的優(yōu)先級高于全局降級處理。

            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 &lt;T&gt; T navigation(Class&lt;? extends T&gt; 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的名字從集合中找到對應(yīng)的RouteMeta并把path和group設(shè)置給postcard,接下來也是給postcard設(shè)置其他各種參數(shù),和上面分析的大同小異。

            path動態(tài)改變

            調(diào)用的方式和降級處理一模一樣,時(shí)機(jī)是在build的時(shí)候。

            參數(shù)自動獲取

            @Autowired
            @JvmField
            var key3: String? = null
            @Autowired
            @JvmField
            var key1: Long = 0L

            ARouter.getInstance().inject(this)

            從文檔中可以知道,按照上面的方式就可以自動獲取各個參數(shù)。關(guān)鍵代碼肯定是在inject方法中,調(diào)用的還是服務(wù)。

            static void inject(Object thiz) {
            AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build(&#34;/arouter/service/autowired&#34;).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í)這個類還是在注解生成類中

            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(&#34;girl&#34;);
            substitute.key1 = substitute.getIntent().getLongExtra(&#34;key1&#34;, substitute.key1);
            }
            }

            還是通過getIntent().getExtra方法獲取的參數(shù),然后把獲取的參數(shù)設(shè)置給當(dāng)前類。

            分析完源碼之后捫心自問一下下面問題是否能回答上來

          3. 1.openLog和openDebug為什么要在init之前?
          4. 2.非Debug環(huán)境如何升級路由表——即添加路由?
          5. 3.為什么要自定義線程池?線程池拋出錯誤的方式有哪幾種?
          6. 4.activity的跳轉(zhuǎn)是怎么實(shí)現(xiàn)的?
          7. 5.fragment實(shí)例是怎么拿到的?為什么不允許攔截?
          8. 6.服務(wù)是如何調(diào)用的?
          9. 7.path能動態(tài)修改嗎?在哪個時(shí)機(jī)修改的?
          10. 8.uri方式是如何跳轉(zhuǎn)的?
          11. 9.路由跳轉(zhuǎn)能否在子線程中?
          12. 10.攔截器怎么實(shí)現(xiàn)的?初始化的時(shí)機(jī)?為什么要在process調(diào)用callback.onContinue()。各個攔截器之間的優(yōu)先級是如何保證的(是在跳轉(zhuǎn)的時(shí)候根據(jù)priority判斷的嗎)
          13. 11.全局降級處理怎么實(shí)現(xiàn)的,和NavigationCallback誰優(yōu)先級更高?
          14. 12.如何對path進(jìn)行預(yù)處理,讓所有路由失效?
          15. 13.實(shí)現(xiàn)多個類繼承PathReplaceService、PretreatmentService實(shí)際會用哪個。
          16. 個人的一些思考,大家可以討論一下

          17. 1.Fragment未做onActivityResult回調(diào)支持,對Fragment的場景還是偏簡單了。
          18. 2.注解實(shí)現(xiàn)類的取名Group和path比較容易混淆。
          19. 3.自動注冊路由表的plugin考慮做增量和并發(fā)編譯處理,效率有待商榷。
          20. 4.插件化是怎么實(shí)現(xiàn)路由表的升級的。
          21. (正文已結(jié)束)

            推薦閱讀:adobe軟件列表

            免責(zé)聲明及提醒:此文內(nèi)容為本網(wǎng)所轉(zhuǎn)載企業(yè)宣傳資訊,該相關(guān)信息僅為宣傳及傳遞更多信息之目的,不代表本網(wǎng)站觀點(diǎn),文章真實(shí)性請瀏覽者慎重核實(shí)!任何投資加盟均有風(fēng)險(xiǎn),提醒廣大民眾投資需謹(jǐn)慎!

            網(wǎng)站簡介 - 聯(lián)系我們 - 營銷服務(wù) - 老版地圖 - 版權(quán)聲明 - 網(wǎng)站地圖
            Copyright.2002-2019 寧夏資訊網(wǎng) 版權(quán)所有 本網(wǎng)拒絕一切非法行為 歡迎監(jiān)督舉報(bào) 如有錯誤信息 歡迎糾正
            九江市| 岳池县| 昌乐县| 富民县| 日照市| 南和县| 满洲里市| 阿巴嘎旗| 全南县| 武清区| 宜昌市| 清水县| 凤山市| 甘谷县| 洪洞县| 涞水县| 西华县| 施秉县| 湘西| 长阳| 龙岩市| 固安县| 宁明县| 多伦县| 咸宁市| 梁河县| 阿城市| 丹寨县| 密云县| 卢湾区| 开江县| 永寿县| 宣威市| 汉寿县| 馆陶县| 大埔县| 洮南市| 佛坪县| 牙克石市| 集安市| 九龙坡区|