Arouter用法及原理2:源码介绍

文章目录


前言

我把Arouter分为开发阶段、编译阶段和运行阶段,分别对应的arouter的三个依赖包
Arouter用法及原理2:源码介绍


一、开发阶段(arouter-annotation)

arouter-annotation主要定义了注解以及相关参数供我们使用

Arouter用法及原理2:源码介绍


二、编译阶段(arouter-compiler)

arouter-compiler扫描使用注解的代码,并且通过javapoet将其转换为java代码
核心代码在Process文件夹中,对应类分别处理几种类型注解的处理
Arouter用法及原理2:源码介绍

Arouter用法及原理2:源码介绍
javapoet是什么?JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件。ARouter利用javapoet生成了各种路由文件。这样就可以在运行的时候去扫描路由文件所在的路径,获取路由文件的类名,调用相关方法初始化路由表。


三、运行阶段(arouter-api)

  1. ARouter.build(path)构建Postcard

  2. LogisticsCenter

    LogisticsCenter.completion(postcard)完善postcard的信息,并且完成了path到activity的转换关系(name与class文件的映射)。

  3. Postcard.navigation()实现跳转

  4. Warehouse 数据仓库,存储映射关系到map中

/**
 * Storage of route meta and other data.
 *
 * @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
 * @version 1.0
 * @since 2017/2/23 下午1:39
 */
class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    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();
    }
}

interceptor的map有些特别,是UniqueKeyTreeMap,其实做的很简单,仅仅是在key(优先级)相同时,抛出指定的异常。因此,记住不要出现优先级相同的interceptor。
Arouter用法及原理2:源码介绍Arouter用法及原理2:源码介绍

四、运行加速(arouter-register)

ARouter的运行阶段是存在缺陷的,缺陷就在于拿到这个Map的过程 我们在使用ARouter时都需要初始化,ARouter所做的即是在初始化时利用反射扫描指定包名下面的所有className,然后再添加map中。

我们分析LogisticsCenter.init的源码可知

1.初次打开时会利用ClassUtils.getFileNameByPackageName通过反射来扫描对应包下的所有className
2.在初次扫描后会存储在SharedPreferences中,这样后续就不需要再扫描了,这也是一个优化

以上两个过程都是耗时操作,即是ARouter初次打开时可能会造成慢的原因(二次打开因为有sp缓存所以不会慢)


public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    //load by plugin first
    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.
        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();
            }

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

于是arouter提供了arouter-register插件解决这个问题。
其基本原理是字节码插桩,通过gradle生成java文件内容插入到源码中,已解决反射的速度问题

//源码代码,插桩前
private static void loadRouterMap() {
	//registerByPlugin一直被置为false
    registerByPlugin = false;
}
//插桩后反编译代码
private static void loadRouterMap() {
    registerByPlugin = false;
    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");
}

上一篇:VHDL编译错误


下一篇:Vue动态路由匹配