ARouter源码分析

2024-02-03 05:48
文章标签 分析 源码 arouter

本文主要是介绍ARouter源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原理

ARouter在编译期的时候,利用自定义注解完成了自动注册。

ARouter的编译

通过RouteProcessor。

process()

process()方法相当于处理器的主函数main(),可以在这个方法中扫描、评估和处理注解的代码,以及生成Java文件。

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {// 判断被注解了的元素集合是否为空if (CollectionUtils.isNotEmpty(annotations)) {// 获取所有被@Route注解的元素集合,元素可以是类、方法、变量等Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);try {logger.info(">>> Found routes, start... <<<");this.parseRoutes(routeElements);} catch (Exception e) {logger.error(e);}return true;}return false;}

然后进入parseRoutes()

parseRoutes()

        if (CollectionUtils.isNotEmpty(routeElements)) {// Perpare the type an so on.logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");rootMap.clear();// TypeElement表示一个类或接口元素TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();// Interface of ARouterTypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);// 获取RouteMeta和RouteType的类信息ClassName routeMetaCn = ClassName.get(RouteMeta.class);ClassName routeTypeCn = ClassName.get(RouteType.class);/*Build input type, format as :```Map<String, Class<? extends IRouteGroup>>```*/// 得到对应的参数类型, 如Map<String, Class<? extends IRouteGroup>>ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(ClassName.get(Map.class),ClassName.get(String.class),ParameterizedTypeName.get(ClassName.get(Class.class),WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))));/*```Map<String, RouteMeta>```*/// 得到对应的参数类型, 如Map<String, RouteMeta>ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(ClassName.get(Map.class),ClassName.get(String.class),ClassName.get(RouteMeta.class));/*Build input param name.*/// 创建输入参数名ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();  // Ps. its param type same as groupParamSpec!/*Build method : 'loadInto'*/// 创建ARouter$$Root$$xxx类中的loadInto()方法MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO).addAnnotation(Override.class).addModifiers(PUBLIC).addParameter(rootParamSpec);//  Follow a sequence, find out metas of group first, generate java file, then statistics them as root.// 按顺序,先找到group的信息,生成Java文件for (Element element : routeElements) {TypeMirror tm = element.asType();Route route = element.getAnnotation(Route.class);RouteMeta routeMeta = null;if (types.isSubtype(tm, type_Activity)) {                               // Activity// 如果是Activitylogger.info(">>> Found activity route: " + tm.toString() + " <<<");// Get all fields annotation by @Autowired// 找到所有注解为@Autowired的成员变量Map<String, Integer> paramsType = new HashMap<>();for (Element field : element.getEnclosedElements()) {if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {// It must be field, then it has annotation, but it not be provider.Autowired paramConfig = field.getAnnotation(Autowired.class);paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));}}// 生成一个对应的RouteMeta,以下也是类似的routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);} else if (types.isSubtype(tm, iProvider)) {         // IProvider// 如果是Providerlogger.info(">>> Found provider route: " + tm.toString() + " <<<");routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);} else if (types.isSubtype(tm, type_Service)) {           // Service// 如果是Servicelogger.info(">>> Found service route: " + tm.toString() + " <<<");routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);} else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {// 如果是Fragmentlogger.info(">>> Found fragment route: " + tm.toString() + " <<<");routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);} else {// 如果都不是,抛出异常throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "].");}// 对RouteMeta进行分类,categories()可以跳到后文去查看categories(routeMeta);// if (StringUtils.isEmpty(moduleName)) {   // Hasn't generate the module name.//     moduleName = ModuleUtils.generateModuleName(element, logger);// }}// 创建ARouter$$Providers$$xxx类中的loadInto()方法MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO).addAnnotation(Override.class).addModifiers(PUBLIC).addParameter(providerParamSpec);// Start generate java source, structure is divided into upper and lower levels, used for demand initialization.// 开始生成Java源文件for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {String groupName = entry.getKey();// 创建ARouter$$Group$$xxx类中的loadInto()方法MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO).addAnnotation(Override.class).addModifiers(PUBLIC).addParameter(groupParamSpec);// Build group method body// 创建方法体Set<RouteMeta> groupData = entry.getValue();for (RouteMeta routeMeta : groupData) {switch (routeMeta.getType()) {// 如果节点类型是Provider,case PROVIDER:  // Need cache provider's super classList<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();for (TypeMirror tm : interfaces) {if (types.isSameType(tm, iProvider)) {   // Its implements iProvider interface himself.// This interface extend the IProvider, so it can be used for mark provider// 如果就是iProvider    loadIntoMethodOfProviderBuilder.addStatement("providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",(routeMeta.getRawType()).toString(),routeMetaCn,routeTypeCn,ClassName.get((TypeElement) routeMeta.getRawType()),routeMeta.getPath(),routeMeta.getGroup());} else if (types.isSubtype(tm, iProvider)) {// This interface extend the IProvider, so it can be used for mark provider// 如果是iProvider的实现类  loadIntoMethodOfProviderBuilder.addStatement("providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",tm.toString(),    // So stupid, will duplicate only save class name.routeMetaCn,routeTypeCn,ClassName.get((TypeElement) routeMeta.getRawType()),routeMeta.getPath(),routeMeta.getGroup());}}break;default:break;}// Make map body for paramsType// 获取RouteMeta中被@Autowired注解的属性集合,用字符串拼接StringBuilder mapBodyBuilder = new StringBuilder();Map<String, Integer> paramsType = routeMeta.getParamsType();if (MapUtils.isNotEmpty(paramsType)) {for (Map.Entry<String, Integer> types : paramsType.entrySet()) {mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");}}String mapBody = mapBodyBuilder.toString();// 向ARouter$$Group$$xxx类中的loadInto()添加方法体loadIntoMethodOfGroupBuilder.addStatement("atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){{" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",routeMeta.getPath(),routeMetaCn,routeTypeCn,ClassName.get((TypeElement) routeMeta.getRawType()),routeMeta.getPath().toLowerCase(),routeMeta.getGroup().toLowerCase());}// Generate groups// 最终生成ARouter$$Group$$XXX的Java文件String groupFileName = NAME_OF_GROUP + groupName;JavaFile.builder(PACKAGE_OF_GENERATE_FILE,TypeSpec.classBuilder(groupFileName).addJavadoc(WARNING_TIPS).addSuperinterface(ClassName.get(type_IRouteGroup)).addModifiers(PUBLIC).addMethod(loadIntoMethodOfGroupBuilder.build()).build()).build().writeTo(mFiler);logger.info(">>> Generated group: " + groupName + "<<<");// 将生成的组文件放在rootmap集合中去,为下面生成ARouter$$Root$$xxx文件做准备rootMap.put(groupName, groupFileName);}if (MapUtils.isNotEmpty(rootMap)) {// Generate root meta by group name, it must be generated before root, then I can find out the class of group.// 遍历rootMap集合,向ARouter$$Root$$xxx的`loadInto()`添加方法体for (Map.Entry<String, String> entry : rootMap.entrySet()) {loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));}}// Wirte provider into disk// 生成ARouter$$Providers$$xxx文件String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;JavaFile.builder(PACKAGE_OF_GENERATE_FILE,TypeSpec.classBuilder(providerMapFileName).addJavadoc(WARNING_TIPS).addSuperinterface(ClassName.get(type_IProviderGroup)).addModifiers(PUBLIC).addMethod(loadIntoMethodOfProviderBuilder.build()).build()).build().writeTo(mFiler);logger.info(">>> Generated provider map, name is " + providerMapFileName + " <<<");// Write root meta into disk.// 生成ARouter$$Root$$xxx文件String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;JavaFile.builder(PACKAGE_OF_GENERATE_FILE,TypeSpec.classBuilder(rootFileName).addJavadoc(WARNING_TIPS).addSuperinterface(ClassName.get(elements.getTypeElement(ITROUTE_ROOT))).addModifiers(PUBLIC).addMethod(loadIntoMethodOfRootBuilder.build()).build()).build().writeTo(mFiler);logger.info(">>> Generated root, name is " + rootFileName + " <<<");}}

编译过后,我们发现会根据以上过程生成的文件:
这里写图片描述

再看一下生成文件中的内容:

public class ARouter$$Group$$service implements IRouteGroup {@Overridepublic void loadInto(Map<String, RouteMeta> atlas) {atlas.put("/service/json", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));}
}public class ARouter$$Group$$tsnt implements IRouteGroup {@Overridepublic void loadInto(Map<String, RouteMeta> atlas) {atlas.put("/tsnt/aroutertest2", RouteMeta.build(RouteType.ACTIVITY, ARouterTest2Activity.class, "/tsnt/aroutertest2", "tsnt", new java.util.HashMap<String, Integer>(){{put("hometown", 8); put("person", 10); put("name", 8); put("age", 3); }}, -1, -2147483648));atlas.put("/tsnt/aroutertest3", RouteMeta.build(RouteType.ACTIVITY, ARouterTest3Activity.class, "/tsnt/aroutertest3", "tsnt", null, -1, -2147483648));}
}public class ARouter$$Providers$$app implements IProviderGroup {@Overridepublic void loadInto(Map<String, RouteMeta> providers) {providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));}
}public class ARouter$$Root$$app implements IRouteRoot {@Overridepublic void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {routes.put("service", ARouter$$Group$$service.class);routes.put("tsnt", ARouter$$Group$$tsnt.class);}
}

确实就是根据parseRoutes()生成的。

categories()

    /*** Sort metas in group.** @param routeMete metas.*/private void categories(RouteMeta routeMete) {// 验证RouteMeta的正确性if (routeVerify(routeMete)) {logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<");// 从groupMap中获取对应的RouteMeta集合Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup());if (CollectionUtils.isEmpty(routeMetas)) {// 如果没有对应的RouteMeta集合,创建一个新的集合Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() {@Overridepublic int compare(RouteMeta r1, RouteMeta r2) {try {return r1.getPath().compareTo(r2.getPath());} catch (NullPointerException npe) {logger.error(npe.getMessage());return 0;}}});// 将RouteMeta加入RouteMeta集合routeMetaSet.add(routeMete);// 将RouteMeta集合加入groupMapgroupMap.put(routeMete.getGroup(), routeMetaSet);} else {routeMetas.add(routeMete);}} else {logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");}}/*** Verify the route meta** @param meta raw meta*/private boolean routeVerify(RouteMeta meta) {// 获取对应的path参数String path = meta.getPath();if (StringUtils.isEmpty(path) || !path.startsWith("/")) {   // The path must be start with '/' and not empty!// 如果为空或者不以"/"开头,返回falsereturn false;}if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)// 如果没有设置对应的group, 从path中获取第一段路径作为group// 例如:path是"/x/y/z",group就是"z"try {String defaultGroup = path.substring(1, path.indexOf("/", 1));if (StringUtils.isEmpty(defaultGroup)) {return false;}meta.setGroup(defaultGroup);return true;} catch (Exception e) {logger.error("Failed to extract default group! " + e.getMessage());return false;}}return true;}

ARouter的初始化

经过编译后,生成了相应的映射文件,ARouter的初始化会将这些文件加载到内存中去,形成一个路由表,以供后面路由查找跳转之用。

init()

    /*** Init, it must be call before used router.*/public static void init(Application application) {if (!hasInit) {// 没被初始化,就去初始化logger = _ARouter.logger;_ARouter.logger.info(Consts.TAG, "ARouter init start.");hasInit = _ARouter.init(application);if (hasInit) {_ARouter.afterInit();}_ARouter.logger.info(Consts.TAG, "ARouter init over.");}}

实际调用_ARouter的init():

    protected static synchronized boolean init(Application application) {mContext = application;LogisticsCenter.init(mContext, executor);logger.info(Consts.TAG, "ARouter init success!");hasInit = true;// It's not a good idea.// if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {//     application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());// }return true;}

其中关键的一句是LogisticsCenter.init(mContext, executor);

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {mContext = context;executor = tpe;try {long startInit = System.currentTimeMillis();Set<String> routerMap;// It will rebuild router map every times when debuggable.if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {// 如果是可测试的,或者是App的新版本,才会去生成新的路由表logger.info(TAG, "Run with debug mode or new install, rebuild router map.");// These class was generate by arouter-compiler.// 查找"com.alibaba.android.arouter.routes"包下的类,就是编译之后ARouter生成的文件routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);if (!routerMap.isEmpty()) {// 如果不为空,存入spcontext.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();}} else {logger.info(TAG, "Load router map from cache.");// 从sp中取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();for (String className : routerMap) {if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {// This one of root elements, load root.// 类名以“com.alibaba.android.arouter.routes.ARouter$$Root”开头,通过反射实例化,并且调用loadInto(),目的将编译生成的ARouter$$Group$$xxx文件加载到内存中,保存在Warehouse.groupsIndex;((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {// Load interceptorMeta// 类名以“com.alibaba.android.arouter.routes.ARouter$$Interceptors”开头,执行编译生成的ARouter$$Interceptors$$xxx的loadInto(),将自定义拦截器类存放在Warehouse.interceptorsIndex中((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {// Load providerIndex// 类名以“com.alibaba.android.arouter.routes.ARouter$$Providers”开头,执行编译生成的ARouter$$Providers$$xxx的loadInto(),将自定义iProvider存放在Warehouse.providersIndex中((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() + "]");}}

总结下来,其实ARouter 的初始化只做了一件事,找到自己编译期产生的清单文件,把 Group 、Interceptor 、Provider 三种清单加载到 Warehouse 内存仓库中。

ARouter的使用

给出官网的示例:

// 1. Simple jump within application (Jump via URL in 'Advanced usage')
ARouter.getInstance().build("/test/activity").navigation();// 2. Jump with parameters
ARouter.getInstance().build("/test/1").withLong("key1", 666L).withString("key3", "888").withObject("key4", new Test("Jack", "Rose")).navigation();

ARouter路由跳转采用链式调用,ARouter.getInstance()其中采用的单例模式,获取ARouter的实例。

build()

    public Postcard build(String path) {return _ARouter.getInstance().build(path);}

最终调用一个重载的方法:

    /*** Build postcard by path and group*/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);}}

最后返回一个Postcard实例对象,继承自之前提到过的的RouteMeta,封装了路径,分组等节点信息:

public final class Postcard extends RouteMeta {// Baseprivate Uri uri;private Object tag;             // A tag prepare for some thing wrong.private Bundle mBundle;         // Data to transformprivate int flags = -1;         // Flags of routeprivate int timeout = 300;      // Navigation timeout, TimeUnit.Secondprivate IProvider provider;     // It will be set value, if this postcard was provider.private boolean greenChannel;private SerializationService serializationService;// Animationprivate Bundle optionsCompat;    // The transition animation of activityprivate int enterAnim;private int exitAnim;……
}

其实build()方法的目的只有一个就是根据路由,封装成Postcard对象,这个对象贯穿之后整个路由过程。

以下是Postcard的navigation():

    /*** Navigation to the route with path in postcard.* No param, will be use application context.*/public Object navigation() {return navigation(null);}

最终调用了_ARouter的navigation():

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {// 补充postcard具体信息,后文会具体分析LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {logger.warning(Consts.TAG, ex.getMessage());if (debuggable()) { // Show friendly tips for user.Toast.makeText(mContext, "There's no route matched!\n" +" Path = [" + postcard.getPath() + "]\n" +" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();}if (null != callback) {// 如果处理postcard失败,通过callback回调失败结果callback.onLost(postcard);} else {    // No callback for this invoke, then we use the global degrade service.// callback为空的情况下,如果有定义全局的降级处理(DegradeService),则使用全局处理// 降级处理也需要我们自己实现DegradeService接口DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}return null;}// 路由处理成功,回调callback.onFound()if (null != callback) {callback.onFound(postcard);}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*/@Overridepublic void onContinue(Postcard postcard) {_navigation(context, postcard, requestCode, callback);}/*** Interrupt process, pipeline will be destory when this method called.** @param exception Reson of interrupt.*/@Overridepublic void onInterrupt(Throwable exception) {if (null != callback) {callback.onInterrupt(postcard);}logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());}});} else {// 最终调用_navigation()完成路由跳转return _navigation(context, postcard, requestCode, callback);}return null;}

进入_navigation():

    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:// Build intentfinal Intent intent = new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras());// Set flags.int flags = postcard.getFlags();if (-1 != flags) {intent.setFlags(flags);} else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}// Navigation in main looper.new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {if (requestCode > 0) {  // Need start for resultActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());} else {ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());}if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) {    // Old version.((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());}if (null != callback) { // Navigation over.callback.onArrival(postcard);}}});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;}

以上很好理解,根据各种不同的type,获取对应的实例或者完成页面跳转。

completion()

然而我们根据Postcard中的信息,如何跳转到对应的页面或者获取对应的实例的呢?

_ARouter的navigation()中有LogisticsCenter.completion(postcard);这样一段代码,它的作用是将信息不完整的Postcard填充完整:

    /*** Completion the postcard by route metas** @param postcard Incomplete postcard, should completion by this method.*/public synchronized static void completion(Postcard postcard) {if (null == postcard) {throw new NoRouteFoundException(TAG + "No postcard!");}// 查找Warehouse仓库的RouteMeta是否已在缓存中RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());if (null == routeMeta) {    // Maybe its does't exist, or didn't load.// 如果不存在,查找仓库的组别清单中是否存在该RouteMeta对应的组别,组别清单已经在初始化的时候加载到仓库中去了Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.if (null == groupMeta) {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()));}// 实例化该组别的类,调用loadInto(),将组别中所有的路由节点加载进仓库Warehouse.routes,缓存IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();iGroupInstance.loadInto(Warehouse.routes);            // 从组别清单中删除已加载的组别,防止重复加载  Warehouse.groupsIndex.remove(postcard.getGroup());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() + "]");}// 当路由节点加载到缓存中去后,重新查找执行else代码,对postcard进行处理completion(postcard);   // Reload}} else {// 给postcard设置destination,type,priority等值,供上面讲解到的_navigation()进行使用// 其中routeMeta是在ARouter$$Group$$xxx的loadInto中创建的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.// 如果通过build(Uri url)进行跳转的话通过解析url,将传参保存进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 @Paramfor (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 uripostcard.withString(ARouter.RAW_URI, rawUri.toString());}switch (routeMeta.getType()) {case PROVIDER:  // if the route is provider, should find its instance// Its provider, so it must be implememt IProvider// 如果是PROVIDER节点类型,从服务节点列表中获取,如果没有,则实例化,并保存在服务节点列表Warehouse.providers中// 并将实例化的对象设置给postcard的provider属性Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();IProvider instance = Warehouse.providers.get(providerMeta);if (null == instance) { // There's no instance of this providerIProvider 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();    // Provider should skip all of interceptorsbreak;case FRAGMENT:postcard.greenChannel();    // Fragment needn't interceptorsdefault:break;}}}

参考:阿里ARouter使用及源码解析

这篇关于ARouter源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/673142

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。