网站需求怎么写,视频转网址在线生成,代写简历哪个平台比较好,wordpress插件安装本地安装本篇文章主要讲解了 ARouter 框架的源码分析#xff0c;包括其初始化过程、核心方法等。
初始化
在使用ARouter的时候我们都会先进行初始化#xff1a;
ARouter.init(this);我们看下 init() 源码#xff1a;
public static void init(Application application) {// 检查…本篇文章主要讲解了 ARouter 框架的源码分析包括其初始化过程、核心方法等。
初始化
在使用ARouter的时候我们都会先进行初始化
ARouter.init(this);我们看下 init() 源码
public static void init(Application application) {// 检查 ARouter 是否已经初始化避免重复初始化if (!hasInit) {// 获取 logger并记录初始化开始的日志logger _ARouter.logger;_ARouter.logger.info(Consts.TAG, ARouter init start.);// 执行 ARouter 的初始化方法并将初始化结果赋值给 hasInithasInit _ARouter.init(application);// 如果初始化成功执行后续的初始化步骤if (hasInit) {_ARouter.afterInit();}// 记录初始化完成的日志_ARouter.logger.info(Consts.TAG, ARouter init over.);}
}真正调用的还是里面的 _ARouter.init()
protected static synchronized boolean init(Application application) {// 将传入的 Application 实例赋值给 mContextmContext application;// 初始化 LogisticsCenter通常是用来管理路由路径和目标组件的调度LogisticsCenter.init(mContext, executor);// 记录初始化成功的日志logger.info(Consts.TAG, ARouter init success!);// 设置初始化标志标记 ARouter 已初始化hasInit true;// 创建一个 Handler 用于在主线程中处理消息mHandler new Handler(Looper.getMainLooper());// 返回初始化成功return true;
}
最终调用了LogisticsCenter的 init() 方法
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {// 保存上下文和线程池实例mContext context;executor tpe;try {// 记录初始化开始时间long startInit System.currentTimeMillis();// 加载路由映射loadRouterMap();// 判断是否使用插件进行自动注册if (registerByPlugin) {logger.info(TAG, Load router map by arouter-auto-register plugin.);} else {SetString routerMap;// 如果是调试模式或者是新版本安装则重新构建路由映射if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {logger.info(TAG, Run with debug mode or new install, rebuild router map.);// 获取路由类文件名这些类是由 arouter-compiler 插件生成的routerMap ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);// 如果有新的路由映射保存到 SharedPreferences 中if (!routerMap.isEmpty()) {context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();}// 更新应用版本信息PackageUtils.updateVersion(context);} 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 HashSetString()));}// 打印路由映射加载完成的日志logger.info(TAG, Find router map finished, map size routerMap.size() , cost (System.currentTimeMillis() - startInit) ms.);startInit System.currentTimeMillis();// 遍历所有路由映射判断并加载对应的组件for (String className : routerMap) {// 判断是否是根元素类若是则加载到 groupsIndexif (className.startsWith(ROUTE_ROOT_PAKCAGE DOT SDK_NAME SEPARATOR SUFFIX_ROOT)) {((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);}// 判断是否是拦截器类若是则加载到 interceptorsIndexelse if (className.startsWith(ROUTE_ROOT_PAKCAGE DOT SDK_NAME SEPARATOR SUFFIX_INTERCEPTORS)) {((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);}// 判断是否是提供者类若是则加载到 providersIndexelse if (className.startsWith(ROUTE_ROOT_PAKCAGE DOT SDK_NAME SEPARATOR SUFFIX_PROVIDERS)) {((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) {// 捕获异常并抛出自定义的 HandlerExceptionthrow new HandlerException(TAG ARouter init logistics center exception! [ e.getMessage() ]);}
}
上面方法主要实现了
通过loadRouterMap方法判断是不是通过arouter-register自动加载路由表如果是通过自动加载的则registerByPlugintrue这里我们先不管通过arouter-register自动加载的方式紧接着通过ClassUtils.getFileNameByPackageName(此处用到了线程池、CountDownLatch面试高频考点)获取到apk中前缀为com.alibaba.android.arouter.routes的类这里面主要是通过判断是不是支持MultiDex如果不支持MultiDex扫描所有的dex文件然后压缩成zip文件然后通过DexFile.loadDex转化成DexFile对象如果支持MultiDex直接new DexFile,然后循环DexFile拿里面的class文件然后过滤出com.alibaba.android.arouter.routes前缀的class并返回。拿到了需要的class类后放到sp里面方便下次不去扫描apk拿class更新版本号将com.alibaba.android.arouter.routes.ARouter$$Root前缀的class类放到Warehouse.groupsIndex中将com.alibaba.android.arouter.routes.ARouter$$Interceptors前缀的class类放到Warehouse.interceptorsIndex中将com.alibaba.android.arouter.routes.ARouter$$Providers前缀的class类放到Warehouse.providersIndex中
_ARouter.afterInit
static void afterInit() {// Trigger interceptor init, use byName.interceptorService (InterceptorService) ARouter.getInstance().build(/arouter/service/interceptor).navigation();}ARouter.build
下面我们来看ARouter的build方法
public Postcard build(String path) {return _ARouter.getInstance().build(path);}返回的是Postcard类型的对象我们看一下里面的 _ARouter.build()
protected Postcard build(String path, String group, Boolean afterReplace) {// 检查路径path和分组group是否为空如果为空则抛出异常if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {throw new HandlerException(Consts.TAG Parameter is invalid!);} else {// 如果 afterReplace 为 false则进行路径替换if (!afterReplace) {// 获取 PathReplaceService 服务实例该服务用于路径的替换操作PathReplaceService pService ARouter.getInstance().navigation(PathReplaceService.class);// 如果 PathReplaceService 服务实例不为空则执行路径替换操作if (null ! pService) {path pService.forString(path); // 调用替换方法替换路径}}// 构建并返回一个 Postcard 对象使用处理后的 path 和 groupreturn new Postcard(path, group);}
}
build 方法根据传入的路径 path 和分组 group 创建一个 Postcard 对象。路径替换如果 afterReplace 为 false则调用 PathReplaceService 服务对路径进行替换。异常处理如果 path 或 group 为空抛出自定义的 HandlerException 异常。
当 afterReplace 为 false 时如果 afterReplace 参数为 false则会进行路径替换。这意味着在构建 Postcard 对象之前会通过 PathReplaceService 服务来替换路径。这个服务允许开发者自定义路径替换逻辑例如根据配置或环境变量动态调整路径。这样做的好处是可以灵活地适应不同的部署环境或业务需求而无需硬编码路径。当 afterReplace 为 true 时如果 afterReplace 参数为 true则不会进行路径替换。这意味着直接使用原始的路径来构建 Postcard 对象。这通常用于那些不需要动态路径替换的场景或者路径已经在其他地方被处理过不需要再次替换。
示例代码
假设你实现了一个 PathReplaceService它的作用是根据不同的环境替换路径中的某些部分
public class PathReplaceServiceImpl implements PathReplaceService {Overridepublic String forString(String path) {// 假设在生产环境中替换 /test/ 为 /prod/if (BuildConfig.DEBUG) {return path; // 开发环境不做替换} else {return path.replace(/test/, /prod/); // 生产环境进行路径替换}}
}然后在调用 ARouter 时使用这个服务
PathReplaceService pService ARouter.getInstance().navigation(PathReplaceService.class);
if (null ! pService) {path pService.forString(path); // 使用服务进行路径替换
}Postcard类
Postcard 类是 ARouter 框架中的一个核心组件它表示一个路由的实体包含了路由的所有信息比如目标路径、分组、传递的数据、动画效果、标志位等。
public final class Postcard extends RouteMeta {// Baseprivate Uri uri;private Object tag; // A tag prepare for some thing wrong. inner params, DO NOT USE!private Bundle mBundle; // Data to transformprivate int flags 0; // 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;private Context context; // May application or activity, check instance type before use it.private String action;Postcard 类继承自 RouteMeta是路由的实际载体包含导航需要的额外信息。
RouteMeta
public class RouteMeta {// 路由类型指示目标是 Activity、Fragment 还是 Provider 等private RouteType type; // 原始类型元素表示目标路由的原始类型如 Activity 或 Fragmentprivate Element rawType; // 目标页面的 Class 类型表示路由请求的具体目标类private Class? destination; // 路由路径唯一标识一个路由如 /app/MainActivityprivate String path; // 路由分组常用于模块化开发避免路径冲突private String group; // 路由的优先级用于在多个路由匹配时确定优先使用哪个路由private int priority; // 额外的信息通常用于存放一些配置信息private int extra; // 路由参数类型的映射存储参数名与其类型的对应关系private MapString, Integer paramsType; // 路由的名称通常用于调试或日志中便于标识路由private String name; // 注入的配置存储需要自动注入的字段信息private MapString, Autowired injectConfig;
}
PostCard.navigation
navigation有很多重载的方法最终都会走_Arouter.navigation
/*** 导航到 postcard 中路径指定的路由。** param context 上下文通常是 Activity 等。*/
public Object navigation(Context context) {return navigation(context, null);
}/*** 导航到 postcard 中路径指定的路由。** param context 上下文通常是 Activity 等。* param callback 导航回调接口。*/
public Object navigation(Context context, NavigationCallback callback) {return ARouter.getInstance().navigation(context, this, -1, callback);
}/*** 导航到 postcard 中路径指定的路由。** param mContext 上下文通常是 Activity 等。* param requestCode startActivityForResult 的请求码。*/
public void navigation(Activity mContext, int requestCode) {navigation(mContext, requestCode, null);
}/*** 导航到 postcard 中路径指定的路由。** param mContext 上下文通常是 Activity 等。* param requestCode startActivityForResult 的请求码。* param callback 导航回调接口。*/
public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}
这几个方法会调用ARouter.navigation public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);}
接着调用_Arouter.navigation
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {// 获取预处理服务实例PretreatmentService pretreatmentService ARouter.getInstance().navigation(PretreatmentService.class);// 如果预处理服务存在并且返回的结果为 false则导航失败取消导航if (null ! pretreatmentService !pretreatmentService.onPretreatment(context, postcard)) {// 预处理失败导航被取消return null;}// 设置 postcard 的上下文如果传入的 context 为 null则使用 mContextpostcard.setContext(null context ? mContext : context);try {// 完成路由的物流处理LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {logger.warning(Consts.TAG, ex.getMessage());// 如果启用了调试模式则显示友好的提示信息给用户if (debuggable()) {runInMainThread(new Runnable() {Overridepublic void run() {// 弹出提示框告知没有找到匹配的路由Toast.makeText(mContext, 没有找到匹配的路由\n 路径 [ postcard.getPath() ]\n 分组 [ postcard.getGroup() ], Toast.LENGTH_LONG).show();}});}// 如果有回调函数调用 onLost 方法if (null ! callback) {callback.onLost(postcard);} else {// 如果没有回调则使用全局的降级服务DegradeService degradeService ARouter.getInstance().navigation(DegradeService.class);if (null ! degradeService) {degradeService.onLost(context, postcard);}}return null;}// 如果有回调函数调用 onFound 方法if (null ! callback) {callback.onFound(postcard);}// 如果不是绿色通道则执行拦截器可能会导致 ANR 问题if (!postcard.isGreenChannel()) {// 执行拦截器interceptorService.doInterceptions(postcard, new InterceptorCallback() {/*** 继续处理** param postcard 路由元数据*/Overridepublic void onContinue(Postcard postcard) {// 调用实际的导航方法_navigation(postcard, requestCode, callback);}/*** 中断处理管道将在此方法被调用时销毁。** param exception 中断原因*/Overridepublic void onInterrupt(Throwable exception) {// 如果有回调调用 onInterrupt 方法if (null ! callback) {callback.onInterrupt(postcard);}// 记录导航失败信息logger.info(Consts.TAG, 导航失败因拦截器中止 : exception.getMessage());}});} else {// 如果是绿色通道直接执行导航return _navigation(postcard, requestCode, callback);}return null;
}
最后会执行_navigation
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {// 获取当前的上下文final Context currentContext postcard.getContext();// 根据 Postcard 的类型执行不同的导航操作switch (postcard.getType()) {case ACTIVITY:// 如果是 Activity 类型构建 Intent 对象final Intent intent new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras()); // 设置 extras 数据// 设置 flagsint flags postcard.getFlags();if (0 ! flags) {intent.setFlags(flags); // 如果有 flags设置到 intent 中}// 如果当前上下文不是 Activity需要设置 FLAG_ACTIVITY_NEW_TASKif (!(currentContext instanceof Activity)) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}// 设置 ActionString action postcard.getAction();if (!TextUtils.isEmpty(action)) {intent.setAction(action); // 如果有 action设置到 intent 中}// 在主线程中启动 ActivityrunInMainThread(new Runnable() {Overridepublic void run() {startActivity(requestCode, currentContext, intent, postcard, callback);}});break;case PROVIDER:// 如果是 Provider 类型直接返回对应的 Providerreturn postcard.getProvider();case BOARDCAST:case CONTENT_PROVIDER:case FRAGMENT:// 如果是 Broadcast、ContentProvider 或 Fragment 类型Class? fragmentMeta postcard.getDestination();try {// 通过反射创建 Fragment 实例Object instance fragmentMeta.getConstructor().newInstance();if (instance instanceof Fragment) {((Fragment) instance).setArguments(postcard.getExtras()); // 设置 extras 数据} 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, 获取 Fragment 实例出错, TextUtils.formatStackTrace(ex.getStackTrace()));}case METHOD:case SERVICE:default:// 如果是 METHOD 或 SERVICE 类型或者未知类型返回 nullreturn null;}return null;
} 参考阿里ARouter全面全面全面解析(使用介绍源码分析设计思路)_arouter init-CSDN博客 已经到底啦