Android项目解耦--路由框架ARouter源码解析

2024-02-09 07:08

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

前言

上一篇文章Android项目解耦–路由框架ARouter的使用讲述了ARouter在项目中的使用,这边文章主要对ARouter的源码进行学习和分析。

ARouter的结构

ARouter主要由三部分组成,包括对外提供的api调用模块、注解模块以及编译时通过注解生产相关的类模块。

  • arouter-annotation注解的声明和信息存储类的模块
  • arouter-compiler编译期解析注解信息并生成相应类以便进行注入的模块
  • arouter-api核心调用Api功能的模块

annotation模块

arouter-annotation.png

RouteInterceptorAutowired都是我们在开发是需要的注解。

compiler模块

arouter-compiler.png

AutoWiredProcessorInterceptorProcessorRouteProcessor分别为annotation模块对应的AutowiredInterceptorRoute在项目编译时产生相关的类文件。

build-source.png

api模块

主要是ARouter具体实现和对外暴露使用的api。api部分我们可以参数上一篇文章Android项目解耦–路由框架ARouter的使用,ARouter实现我们具体在下面讲解。

ARouter的工作流程

arouter-init.png

Arouter初始化

public final class ARouter {/*** 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初始化

final class _ARouter {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初始化

public class LogisticsCenter {/*** LogisticsCenter init, load all metas in memory. Demand initialization*/public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {mContext = context;executor = tpe;try {long startInit = System.currentTimeMillis();Set<String> routerMap;//debug或者版本更新的时候每次都重新加载router信息// 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 generate by arouter-compiler.//加载alibaba.android.arouter.routes包下载的类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 finish.} 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();for (String className : routerMap) {if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {// This one of root elements, load root. //导入ARouter$$Root$$app.java,初始化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//导入ARouter$$Interceptors$$app.java,初始化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//导入ARouter$$Providers$$app.java,初始化Warehouse.providersIndex集合((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);}}/*******部分代码省略********/} catch (Exception e) {throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");}}
}

ARouter的结构

结构.png

ARouter、Postcard、LogisticsCenter、DegradeService、PathReplaceService、InterceptroService这五个部分基本构成了ARouter的主体架构。

ARouter(_ARouter)模块

ARouter主要提供对外调用的api,_ARouter路由协议的具体实现类。

获取服务

final class _ARouter {protected <T> T navigation(Class<? extends T> service) {try {Postcard postcard = LogisticsCenter.buildProvider(service.getName());// Compatible 1.0.5 compiler sdk.if (null == postcard) { // No service, or this service in old version.postcard = LogisticsCenter.buildProvider(service.getSimpleName());}LogisticsCenter.completion(postcard);return (T) postcard.getProvider();} catch (NoRouteFoundException ex) {logger.warning(Consts.TAG, ex.getMessage());return null;}}
}

跳转协议

final class _ARouter {protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {/**************部分代码省略***************/if (null != callback) {callback.onLost(postcard);} else {    // No callback for this invoke, then we use the global degrade service.DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}return null;}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() {@Overridepublic void onContinue(Postcard postcard) {_navigation(context, postcard, requestCode, callback);}@Overridepublic void onInterrupt(Throwable exception) {//中断处理if (null != callback) {callback.onInterrupt(postcard);}}});} else {return _navigation(context, postcard, requestCode, callback);}return null;}private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {//没有上下文环境,就用Application的上下文环境final Context currentContext = null == context ? mContext : context;switch (postcard.getType()) {case ACTIVITY:// Build intent 构建跳转的intentfinal Intent intent = new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras());// Set flags. 设置flagint flags = postcard.getFlags();if (-1 != flags) {intent.setFlags(flags);} else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.//如果上下文不是Activity,则添加FLAG_ACTIVITY_NEW_TASK的flagintent.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;}
}

Postcard模块

postcard.png

Postcard主要为信息的携带者,内容是在构造一次路由信息的时候生产的,其继承于RouteMetaRouteMeta是在代码编译时生成的内容,主要在初始化WareHouse时对跳转信息做了缓存。

class Warehouse {// Cache route and metasstatic Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();static Map<String, RouteMeta> routes = new HashMap<>();// Cache providerstatic Map<Class, IProvider> providers = new HashMap<>();static Map<String, RouteMeta> providersIndex = new HashMap<>();// Cache interceptorstatic 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();}
}

我们先来看一下一些基础类的信息:

router-data.png

/*** DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$activity implements IRouteGroup {@Overridepublic void loadInto(Map<String, RouteMeta> atlas) {atlas.put("/Example1Activity", RouteMeta.build(RouteType.ACTIVITY, Example1Activity.class, "/example1activity", "activity", null, -1, 10));atlas.put("/activity/FragActivity", RouteMeta.build(RouteType.ACTIVITY, FragActivity.class, "/activity/fragactivity", "activity", null, -1, -2147483648));atlas.put("/activity/MainActivity", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/activity/mainactivity", "activity", null, -1, -2147483648));atlas.put("/activity/ParamsCallActivity", RouteMeta.build(RouteType.ACTIVITY, ParamsCallActivity.class, "/activity/paramscallactivity", "activity", new java.util.HashMap<String, Integer>(){{put("obj", 10); put("name", 8); put("girl", 0); put("age", 3); }}, -1, -2147483648));atlas.put("/activity/WebViewActivity", RouteMeta.build(RouteType.ACTIVITY, WebViewActivity.class, "/activity/webviewactivity", "activity", null, -1, -2147483648));}
}

LogisticsCenter

逻辑中心涉路由信息的处理。主要分为两个部分初始化路由信息(初始化时已经讲述过),和路由跳转时的路由功能。

final class LogisticsCenter {/*** 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!");}//从仓库中获取路由信息RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());if (null == routeMeta) {    // Maybe its does't exist, or didn't load.//导入改路由分组信息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()));}//从缓存中读取该分组的路由信息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() + "]");}completion(postcard);   // Reload}} else {//将路由信息导入到卡片中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 @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 IProviderClass<? 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 {//通过反射构造Providerprovider = providerMeta.getConstructor().newInstance();provider.init(mContext);//缓存provider路由信息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;}}}
}

DegradeService(降级容错服务)

@Route(path = DegradeServiceImpl.PATH)
public class DegradeServiceImpl implements DegradeService {public static final String PATH = "/service/DegradeServiceImpl";@Overridepublic void onLost(Context context, Postcard postcard) {if (context != null && postcard.getGroup().equals("activity")) {ActivityCompat.startActivity(context, new Intent(context, DefalutActivity.class), null);}}@Overridepublic void init(Context context) {}
}

路由寻址出现问题的时候的容错处理。

final class _ARouter {protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {/***********部分代码省略************/if (null != callback) {callback.onLost(postcard);} else {    // No callback for this invoke, then we use the global degrade service.DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}return null;}/***********部分代码省略************/}
}

PathReplaceService

@Route(path = PathReplaceServiceImpl.PATH)
public class PathReplaceServiceImpl implements PathReplaceService {public static final String PATH = "/ddservice/PathReplaceServiceImpl";private Map<String, String> pathMap;@Overridepublic String forString(String path) {String result = pathMap.containsKey(path) ? pathMap.get(path) : path;return result;}@Overridepublic Uri forUri(Uri uri) {return uri;}public void replacePath(String sourcePath, String targetPath) {pathMap.put(sourcePath, targetPath);}@Overridepublic void init(Context context) {pathMap = new HashMap<>();}public Map<String, String> getReplacePathMap() {return Collections.unmodifiableMap(pathMap);}
}

从定义的类名我们可以看出来就是替换路径的服务,在构造路由协议的时候首先都会使用PathReplaceService服务进行地址替换。

final class _ARouter {/*** Build postcard by path and default group*/protected Postcard build(String path) {if (TextUtils.isEmpty(path)) {throw new HandlerException(Consts.TAG + "Parameter is invalid!");} else {PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {path = pService.forString(path);}return build(path, extractGroup(path));}}/*** Build postcard by uri*/protected Postcard build(Uri uri) {if (null == uri || TextUtils.isEmpty(uri.toString())) {throw new HandlerException(Consts.TAG + "Parameter invalid!");} else {PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {uri = pService.forUri(uri);}return new Postcard(uri.getPath(), extractGroup(uri.getPath()), uri, null);}}
}

Interceptor拦截器

在ARouter模块的时候讲述Interceptor的使用,如果本次路由跳转不是走的绿色通道那么则会触发拦截器进行过滤。

final class _ARouter {protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {/************部分代码省略************/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 {return _navigation(context, postcard, requestCode, callback);}return null;}
}

拦截器的初始化

InterceptorServiceImpl的构造时间:

final class _ARouter {static void afterInit() {// Trigger interceptor init, use byName.interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();}
}

InterceptorServiceImpl的init方法:

@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {@Overridepublic void init(final Context context) {LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {//循环遍历仓库中的拦截器for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {Class<? extends IInterceptor> interceptorClass = entry.getValue();try {//反射机制构造自定义的每一个拦截器实例IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();iInterceptor.init(context);//并将其添加在缓存中Warehouse.interceptors.add(iInterceptor);} catch (Exception ex) {throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");}}interceptorHasInit = true;logger.info(TAG, "ARouter interceptors init over.");synchronized (interceptorInitLock) {interceptorInitLock.notifyAll();}}}});}
}

拦截器的工作过程

@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {@Overridepublic void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {//检测是否初始化完所有的烂机器checkInterceptorsInitStatus();//没有完成正常的初始化,抛异常if (!interceptorHasInit) {callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));return;}//顺序遍历每一个拦截器,LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());try {_excute(0, interceptorCounter, postcard);interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);//拦截器的遍历终止之后,如果有还有没有遍历的拦截器,则表示路由事件被拦截if (interceptorCounter.getCount() > 0) {    // Cancel the navigation this time, if it hasn't return anythings.callback.onInterrupt(new HandlerException("The interceptor processing timed out."));} else if (null != postcard.getTag()) {    // Maybe some exception in the tag.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 < Warehouse.interceptors.size()) {IInterceptor iInterceptor = Warehouse.interceptors.get(index);iInterceptor.process(postcard, new InterceptorCallback() {@Overridepublic void onContinue(Postcard postcard) {// Last interceptor excute over with no exception.counter.countDown();//如果当前没有拦截过滤,那么使用下一个拦截器_excute(index + 1, counter, postcard);  // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know.}@Overridepublic void onInterrupt(Throwable exception) {// Last interceptor excute over with fatal exception.postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());    // save the exception message for backup.counter.cancel();}});}}
}

Autowired的数据传输和自动注入

将数据放入intent中,然后getintent获取赋值。

/*** DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ParamsCallActivity$$ARouter$$Autowired implements ISyringe {private SerializationService serializationService;@Overridepublic void inject(Object target) {serializationService = ARouter.getInstance().navigation(SerializationService.class);ParamsCallActivity substitute = (ParamsCallActivity)target;substitute.name = substitute.getIntent().getStringExtra("name");substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);substitute.boy = substitute.getIntent().getBooleanExtra("girl", substitute.boy);if (null != serializationService) {substitute.obj = serializationService.parseObject(substitute.getIntent().getStringExtra("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Person>(){}.getType());} else {Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'ParamsCallActivity' , then you should implement 'SerializationService' to support object auto inject!");}}
}

数据类型转化

Postcard添加路由参数的时候都是放在Bundle中的,传递Object对象的时候是通过SerializationService服务先将其转化为String类型,然后在获取的时候再进反序列化。

public class TypeUtils {private Types types;private Elements elements;private TypeMirror parcelableType;public TypeUtils(Types types, Elements elements) {this.types = types;this.elements = elements;parcelableType = this.elements.getTypeElement(PARCELABLE).asType();}//将数据类型转化为int值public int typeExchange(Element element) {TypeMirror typeMirror = element.asType();// Primitiveif (typeMirror.getKind().isPrimitive()) {return element.asType().getKind().ordinal();}switch (typeMirror.toString()) {case BYTE:return TypeKind.BYTE.ordinal();case SHORT:return TypeKind.SHORT.ordinal();case INTEGER:return TypeKind.INT.ordinal();case LONG:return TypeKind.LONG.ordinal();case FLOAT:return TypeKind.FLOAT.ordinal();case DOUBEL:return TypeKind.DOUBLE.ordinal();case BOOLEAN:return TypeKind.BOOLEAN.ordinal();case STRING:return TypeKind.STRING.ordinal();default:    // Other side, maybe the PARCELABLE or OBJECT.if (types.isSubtype(typeMirror, parcelableType)) {  // PARCELABLEreturn TypeKind.PARCELABLE.ordinal();} else {    // For othersreturn TypeKind.OBJECT.ordinal();}}}
}

缓存的数据模板,用int值表示数据类型进行存储:

atlas.put("/activity/ParamsCallActivity", RouteMeta.build(RouteType.ACTIVITY, ParamsCallActivity.class, "/activity/paramscallactivity", "activity", new java.util.HashMap<String, Integer>(){{put("obj", 10); put("name", 8); put("girl", 0); put("age", 3); }}, -1, -2147483648));

编译时的注解过程中执行数据获取:

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends AbstractProcessor {private String buildStatement(String originalValue, String statement, int type, boolean isActivity) {if (type == TypeKind.BOOLEAN.ordinal()) {statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")") : ("getBoolean($S)"));} else if (type == TypeKind.BYTE.ordinal()) {statement += (isActivity ? ("getByteExtra($S, " + originalValue + "") : ("getByte($S)"));} else if (type == TypeKind.SHORT.ordinal()) {statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")") : ("getShort($S)"));} else if (type == TypeKind.INT.ordinal()) {statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")") : ("getInt($S)"));} else if (type == TypeKind.LONG.ordinal()) {statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")") : ("getLong($S)"));}else if(type == TypeKind.CHAR.ordinal()){statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")") : ("getChar($S)"));} else if (type == TypeKind.FLOAT.ordinal()) {statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")") : ("getFloat($S)"));} else if (type == TypeKind.DOUBLE.ordinal()) {statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")") : ("getDouble($S)"));} else if (type == TypeKind.STRING.ordinal()) {statement += (isActivity ? ("getStringExtra($S)") : ("getString($S)"));} else if (type == TypeKind.PARCELABLE.ordinal()) {statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));} else if (type == TypeKind.OBJECT.ordinal()) {statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())";}return statement;}
}

多dex的支持

可查看multidex源码:

public class ClassUtils {  /*** Identifies if the current VM has a native support for multidex, meaning there is no need for* additional installation by this library.** @return true if the VM handles multidex*/private static boolean isVMMultidexCapable() {boolean isMultidexCapable = false;String vmName = null;try {if (isYunOS()) {    // YunOS需要特殊判断vmName = "'YunOS'";isMultidexCapable = Integer.valueOf(System.getProperty("ro.build.version.sdk")) >= 21;} else {    // 非YunOS原生AndroidvmName = "'Android'";String versionString = System.getProperty("java.vm.version");if (versionString != null) {Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString);if (matcher.matches()) {try {int major = Integer.parseInt(matcher.group(1));int minor = Integer.parseInt(matcher.group(2));isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR)|| ((major == VM_WITH_MULTIDEX_VERSION_MAJOR)&& (minor >= VM_WITH_MULTIDEX_VERSION_MINOR));} catch (NumberFormatException ignore) {// let isMultidexCapable be false}}}}} catch (Exception ignore) {}Log.i(Consts.TAG, "VM with name " + vmName + (isMultidexCapable ? " has multidex support" : " does not have multidex support"));return isMultidexCapable;}
}

InstantRun支持

在自己运行过程中,貌似InstantRun是不生效的。com.android.tools.fd.runtime.Paths这个类是不存在的。

public class ClassUtils {  /*** Get instant run dex path, used to catch the branch usingApkSplits=false.*/private static List<String> tryLoadInstantRunDexFile(ApplicationInfo applicationInfo) {List<String> instantRunSourcePaths = new ArrayList<>();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && null != applicationInfo.splitSourceDirs) {// add the split apk, normally for InstantRun, and newest version.instantRunSourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));Log.d(Consts.TAG, "Found InstantRun support");} else {try {// This man is reflection from Google instant run sdk, he will tell me where the dex files go.Class pathsByInstantRun = Class.forName("com.android.tools.fd.runtime.Paths");Method getDexFileDirectory = pathsByInstantRun.getMethod("getDexFileDirectory", String.class);String instantRunDexPath = (String) getDexFileDirectory.invoke(null, applicationInfo.packageName);File instantRunFilePath = new File(instantRunDexPath);if (instantRunFilePath.exists() && instantRunFilePath.isDirectory()) {File[] dexFile = instantRunFilePath.listFiles();for (File file : dexFile) {if (null != file && file.exists() && file.isFile() && file.getName().endsWith(".dex")) {instantRunSourcePaths.add(file.getAbsolutePath());}}Log.d(Consts.TAG, "Found InstantRun support");}} catch (Exception e) {Log.e(Consts.TAG, "InstantRun support error, " + e.getMessage());}}return instantRunSourcePaths;}
}

总结

整个ARouter没有多少东西,但是值得我们学习的却有很多。框架对整个路由功能的模块划分以及像拦截器、降级处理、替换路径以及分组加载等。

RouterHelper GitHub地址

文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦~!~!

想阅读作者的更多文章,可以查看我 个人博客 和公共号:

振兴书城

这篇关于Android项目解耦--路由框架ARouter源码解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

Go路由注册方法详解

《Go路由注册方法详解》Go语言中,http.NewServeMux()和http.HandleFunc()是两种不同的路由注册方式,前者创建独立的ServeMux实例,适合模块化和分层路由,灵活性高... 目录Go路由注册方法1. 路由注册的方式2. 路由器的独立性3. 灵活性4. 启动服务器的方式5.

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查