配置
kotlin项目:
module App:
代码语言:javascript代码运行次数:0运行复制<code class="javascript">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'}</code><code class="javascript">//项目根目录build.gradledependencies { classpath "com.alibaba:arouter-register:1.0.2"}</code>三个关键阶段

ARouter源码分析.png
自定义处理器工作流程:

整体流程.png
自定义处理器源码分析:结构图

ARoute注解源码解析-1.png
生成类的关系
调用类:
代码语言:javascript代码运行次数:0运行复制<code class="javascript">@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" }}</code>ARouter生成类:
代码语言:javascript代码运行次数:0运行复制<code class="javascript">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); }}</code>这段代码最终会利用当前类名和规则,拼接成KotlinTestActivity$$ARouter$$Autowired的全类名,然后利用反射传进对象。然后执行inject(this); 然后里面会初始化传输字段序列化服务,然后强转target,开始赋值数据
生成类文件的关系

RouteProcessor生成文件.png
由此可总结出下面整体工作流程
ARouter整体工作流程
整体工作流程.png
运行时原理分析初始化工作流程分析代码语言:javascript代码运行次数:0运行复制<code class="javascript"> //初始化 ARouter.init(getApplication()); _ARouter.init(application) LogisticsCenter.init(mContext, executor) </code>
LogisticsCenter.init(mContext, executor):
<code class="javascript">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() + "]"); } }</code>可以看出没加载AutoWired文件,也就是说@AutoWired注解字段 在inject()时去创建对象赋值的。 反射找到对象并将Warehouse中的结合作为参数传递进入,把信息装载到内存。注意,这里只是加载了信息,但信息里面的具体内容并未创建。什么意思呢?以Provider为例:
<code class="javascript">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)); }}</code>反射生成ARouter$$Providers$$modulejava对象,但我们用的是com.alibaba.android.arouter.demo.service.HelloServiceHelloService这个具体类。但这个类这是并未实例化,只有用到的时候才回去实例化创建。其他同理。
LogisticsCenter.init(mContext, executor): 还用到两个重要的类和方法: ClassUtils/Warehouse 1. ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
<code class="javascript">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; }</code>如果初始化加载流程没有走完,路由操作将会阻塞,直到加载流程完成
Warehouse 相当于一个加载信息装载的容器类
<code class="javascript">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(); }}</code>
整体工作流程.png
路由过程源码分析代码语言:javascript代码运行次数:0运行复制<code class="javascript"> ARouter.getInstance() .build("/kotlin/test") .withString("name", "老王") .withInt("age", 23) .navigation();</code>.build("/kotlin/test") 查找分组,构建Postcard对象。
<code class="javascript"> 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); } } </code>extractGroup(path):
<code class="javascript"> 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; } }</code>build(path, extractGroup(path), true);:
<code class="javascript"> 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); } }</code>创建:Postcard对象
构建参数mBundle对象。
.navigation(); 运行在异步线程中
<code class="javascript"> 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; }</code>LogisticsCenter.completion(postcard);
<code class="javascript">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); } }</code>_navigation(postcard, requestCode, callback);
<code class="javascript"> 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; }</code>路由结束。

整体工作流程(2).png

图片.png
以上就是一图抵千言《ARouter简明扼要原理分析》的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号