美文网首页安卓
一图抵千言《ARouter简明扼要原理分析》

一图抵千言《ARouter简明扼要原理分析》

作者: g小志 | 来源:发表于2022-03-11 17:52 被阅读0次

    配置

    Kotlin项目:

    module App:

    apply plugin: 'kotlin-kapt'
    
    defaultConfig{
     javaCompileOptions {
       annotationProcessorOptions {
       //AROUTER_MODULE_NAME必配项 用于拼接生成文件名 AROUTER_GENERATE_DOC 
       // AROUTER_GENERATE_DOC = enable 生成Json文档
       // 生成的文档路径 : build/generated/source/apt/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json
       arguments = [AROUTER_MODULE_NAME:project_name,AROUTER_GENERATE_DOC:"enable"]
         }
       }
    }
    
    dependencies{
      api 'com.alibaba:arouter-api:1.5.0'
      kapt 'com.alibaba:arouter-compiler:1.2.2'
    }
    
    
    //项目根目录build.gradle
    dependencies {
      classpath "com.alibaba:arouter-register:1.0.2"
    }
    
    

    源码流程分析

    三个关键阶段

    ARouter源码分析.png

    自定义处理器工作流程:

    整体流程.png
    自定义处理器源码分析:结构图
    ARoute注解源码解析-1.png 生成类的关系

    调用类:

    
    @Route(path = "/kotlin/test")
    class KotlinTestActivity : Activity() {
    
        @Autowired
        @JvmField var name: String? = null
        @Autowired
        @JvmField var age: Int? = 0
    
        override fun onCreate(savedInstanceState: Bundle?) {
            ARouter.getInstance().inject(this)  // Start auto inject.
    
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_kotlin_test)
    
            content.text = "name = $name, age = $age"
        }
    }
    
    

    ARouter生成类:

    
    
    public class KotlinTestActivity$$ARouter$$Autowired implements ISyringe {
      private SerializationService serializationService;
    
      @Override
      public void inject(Object target) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        KotlinTestActivity substitute = (KotlinTestActivity)target;
        substitute.name = substitute.getIntent().getExtras() == null ? substitute.name : substitute.getIntent().getExtras().getString("name", substitute.name);
        substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
      }
    }
    

    ARouter.getInstance().inject(this)

    这段代码最终会利用当前类名和规则,拼接成KotlinTestActivity$$ARouter$$Autowired的全类名,然后利用反射传进对象。然后执行inject(this); 然后里面会初始化传输字段序列化服务,然后强转target,开始赋值数据

    生成类文件的关系

    RouteProcessor生成文件.png
    由此可总结出下面整体工作流程

    ARouter整体工作流程

    整体工作流程.png

    运行时原理分析

    初始化工作流程分析

      //初始化
      ARouter.init(getApplication());
      
      _ARouter.init(application)   
    
      LogisticsCenter.init(mContext, executor)  
      
      
    

    LogisticsCenter.init(mContext, executor):

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            executor = tpe;
    
            try {
                long startInit = System.currentTimeMillis();
                //load by plugin first
                loadRouterMap();
                if (registerByPlugin) {
                    logger.info(TAG, "Load router map by arouter-auto-register plugin.");
                } else {
                    //1 生成文件所有文件的全类名字符串集合
                    Set<String> routerMap;
    
                    // It will rebuild router map every times when debuggable.
                    if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                        logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                        // These class was generated by arouter-compiler.
                        //2. 赋值集合
                        routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                        if (!routerMap.isEmpty()) {
                            context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                        }
    
                        PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                    } else {
                        logger.info(TAG, "Load router map from cache.");
                        routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                    }
    
                    logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                    startInit = System.currentTimeMillis();
    
                     //3. 遍历集合
                    for (String className : routerMap) {
                    // 这里装在了3中类别的文件: (1) Root文件
                        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                            // This one of root elements, load root.
                            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                            //(2) Interceptor 文件
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                            // Load interceptorMeta
                            ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                             // //(3) Provider 文件  
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                            // Load providerIndex
                            ((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() + "]");
            }
        }
    

    可以看出没加载AutoWired文件,也就是说@AutoWired注解字段 在inject()时去创建对象赋值的。
    反射找到对象并将Warehouse中的结合作为参数传递进入,把信息装载到内存。注意,这里只是加载了信息,但信息里面的具体内容并未创建。什么意思呢?以Provider为例:

    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));
      }
    }
    

    反射生成ARouter$$Providers$$modulejava对象,但我们用的是com.alibaba.android.arouter.demo.service.HelloServiceHelloService这个具体类。但这个类这是并未实例化,只有用到的时候才回去实例化创建。其他同理。

    LogisticsCenter.init(mContext, executor): 还用到两个重要的类和方法: ClassUtils/Warehouse
    1. ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);

    public static Set<String> getFileNameByPackageName(Context context, final String packageName) 
    throws PackageManager.NameNotFoundException, IOException, InterruptedException {
            final Set<String> classNames = new HashSet<>();
    
            List<String> paths = getSourcePaths(context);
            //线程同步
            final CountDownLatch parserCtl = new CountDownLatch(paths.size());
    
            for (final String path : paths) {
                DefaultPoolExecutor.getInstance().execute(new Runnable() {
                    @Override
                    public void run() {
                    //Dex文件
                        DexFile dexfile = null;
    
                        try {
                            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);
                            }
    
                            Enumeration<String> dexEntries = dexfile.entries();
                            while (dexEntries.hasMoreElements()) {
                                String className = dexEntries.nextElement();
                                //核心判断 packageName是我们上面传入的参数ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"
                                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;
        }
    

    如果初始化加载流程没有走完,路由操作将会阻塞,直到加载流程完成

    Warehouse 相当于一个加载信息装载的容器类

    class Warehouse {
        // Cache route and metas  
        //groupsIndex 装载ARouter$$Root$$moduleName 中的Root文件  <groupName,Group.class>
        static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
        //routes 按需加载完成后 把加载的数据存到routes 集合中,等项目中用到的时候,找到集合中需要的元素 再去实例化对象
        static Map<String, RouteMeta> routes = new HashMap<>();
    
        // Cache provider
       //项目中用到的时候,找到集合中需要的元素 再去实例化对象 
        static Map<Class, IProvider> providers = new HashMap<>();
        // //每个服务的原始信息加载完成后存放到这里
        static Map<String, RouteMeta> providersIndex = new HashMap<>();
    
        // Cache interceptor   
        static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
        static List<IInterceptor> interceptors = new ArrayList<>();
    
        static void clear() {
            routes.clear();
            groupsIndex.clear();
            providers.clear();
            providersIndex.clear();
            interceptors.clear();
            interceptorsIndex.clear();
        }
    }
    
    整体工作流程.png

    路由过程源码分析

        ARouter.getInstance()
                            .build("/kotlin/test")
                            .withString("name", "老王")
                            .withInt("age", 23)
                            .navigation();
    

    .build("/kotlin/test") 查找分组,构建Postcard对象。

       protected Postcard build(String path) {
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
            // 重定向路由路径Service 如果想自定义 则实现PathReplaceService 
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                //通过forString(path) 返回修改后的Path
                    path = pService.forString(path);
                }
                //继续往下走 
                return build(path, extractGroup(path), true);
            }
        }   
        
    

    extractGroup(path):

     private String extractGroup(String path) {
            if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
                throw new HandlerException(Consts.TAG + "Extract the default group failed, the path must be start with '/' and contain more than 2 '/'!");
            }
    
            try {
            //关键代码 defaultGroup 默认分组 以路由路径 第一个节点为分组名称
                String defaultGroup = path.substring(1, path.indexOf("/", 1));
                if (TextUtils.isEmpty(defaultGroup)) {
                    throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");
                } else {
                    return defaultGroup;
                }
            } catch (Exception e) {
                logger.warning(Consts.TAG, "Failed to extract default group! " + e.getMessage());
                return null;
            }
        }
    

    build(path, extractGroup(path), true);:

      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 pService = ARouter.getInstance().navigation(PathReplaceService.class);
                    if (null != pService) {
                        path = pService.forString(path);
                    }
                }
                return new Postcard(path, group);
            }
        }
    

    创建:Postcard对象

      .withString("name", "老王").withInt("age", 23)
    

    构建参数mBundle对象。

    .navigation(); 运行在异步线程中

     protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            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 {
            //给Postcard赋值其他数据
                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();
                        }
                    });
                }
    
                if (null != callback) {
                // 路由回调 如果不为空
                    callback.onLost(postcard);
                } else {
                    // No callback for this invoke, then we use the global degrade service.
                    //反射创建全局降级服务  回调 onLost方法
                    DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                    if (null != degradeService) {
                        degradeService.onLost(context, postcard);
                    }
                }
    
                return null;
            }
    
            if (null != callback) {
            //回调路由成功的方法
                callback.onFound(postcard);
            }
             //如果绿色通道为false 则添加拦截器 
            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);

    public synchronized static void completion(Postcard postcard) {
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
            //routes是加载信息 但为实例化对象 之前提过  所以这里第一次肯定为空
            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 {
                    // 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()));
                        }
                        //对Warehouse.routes初始化 实例化分组对象 获取数据
                        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 {
            //给postcard赋值其他信息
                postcard.setDestination(routeMeta.getDestination());
                postcard.setType(routeMeta.getType());
                postcard.setPriority(routeMeta.getPriority());
                postcard.setExtra(routeMeta.getExtra());
    
                Uri rawUri = postcard.getUri();
                if (null != rawUri) {   // Try to set params into bundle.
                    Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                    Map<String, Integer> paramsType = routeMeta.getParamsType();
    
                    if (MapUtils.isNotEmpty(paramsType)) {
                        // Set value by its type, just for params which annotation by @Param
                        for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                            setValue(postcard,
                                    params.getValue(),
                                    params.getKey(),
                                    resultMap.get(params.getKey()));
                        }
    
                        // Save params name which need auto inject.
                        postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                    }
    
                    // Save raw uri
                    postcard.withString(ARouter.RAW_URI, rawUri.toString());
                }
                 //类型判断 PROVIDER类型实例化对象 PROVIDER/FRAGMENT默认开启通道,不经过拦截
                switch (routeMeta.getType()) {
                    case PROVIDER:  // if the route is provider, should find its instance
                        // Its provider, so it must implement IProvider
                        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                        IProvider instance = Warehouse.providers.get(providerMeta);
                        if (null == instance) { // There's no instance of this provider
                            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);
                        postcard.greenChannel();    // Provider should skip all of interceptors
                        break;
                    case FRAGMENT:
                        postcard.greenChannel();    // Fragment needn't interceptors
                    default:
                        break;
                }
            }
        }
    
     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.routes初始化 实例化分组对象 获取数据
                Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(groupName);
            }
    
            // cover old group.
            if (null != group) {
                group.loadInto(Warehouse.routes);
            }
        }
    

    _navigation(postcard, requestCode, callback);

      private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            final Context currentContext = postcard.getContext();
    
    //判断路由类型
            switch (postcard.getType()) {
                case ACTIVITY:
                    // 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)) {
                    //context如果是Application 那么新建任务栈
                        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() {
                        //Activity则调用startActivity
                            startActivity(requestCode, currentContext, intent, postcard, callback);
                        }
                    });
    
                    break;
                case PROVIDER:
                //返回LogisticsCenter.completion(postcard)方法中创建的对象
                    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());
                        }
     //反射返回fragment实例
                        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;
        }
    

    路由结束。

    整体工作流程(2).png 图片.png

    相关文章

      网友评论

        本文标题:一图抵千言《ARouter简明扼要原理分析》

        本文链接:https://www.haomeiwen.com/subject/lhhhdrtx.html