【Android】ARouter的使用及源码解析

文章目录

  • 简介
    • 介绍
    • 作用
  • 原理
    • 关系
  • 使用
    • 添加依赖和配置
    • 初始化SDK
    • 添加注解在目标界面
    • 跳转界面不带参
    • 跳转界面含参
    • 处理返回结果
  • 源码
  • 基本流程
    • getInstance()
    • build()
    • navigation()
    • _navigation()
    • Warehouse
  • ARouter初始化
    • init
    • 帮助类
      • 根帮助类
      • 组帮助类
    • completion
  • 总结

简介

介绍

ARouter 是阿里巴巴开源的一款 Android 路由框架,专为组件化架构设计,用于模块之间的页面跳转和服务通信。

ARouter 是路由系统,给无依赖的双方提供通信和路由的能力

作用

  1. 页面路由(页面跳转)
    1. 通过简单的路由配置,实现模块间页面跳转,避免直接依赖具体类,降低耦合度。
    2. 支持跨模块的页面跳转,即使页面所属模块在不同的 APK 中。
  2. 服务发现与调用
    1. 提供服务注册与发现机制,可以实现模块间的接口调用。
    2. 通过依赖注入机制简化服务调用流程,提升开发效率。
  3. 动态传参
    1. 支持页面跳转时传递参数(基本类型、对象等)。
    2. 支持通过注解方式接收参数,省去解析逻辑。

原理

关系

img

  • 1.注册

B界面将类的信息,通过key-value的形式,注册到arouter中。

  • 2.查询

A界面将类信息与额外信息(传输参数、跳转动画等),通过key传递至arouter中,并查询对应需要跳转类的信息。

  • 3.结合

将A界面类信息、参数与B界面的类信息进行封装结合。

  • 4.跳转

将结合后的信息,使用startActivity实现跳转。

使用

添加依赖和配置

android {defaultConfig {...javaCompileOptions {annotationProcessorOptions {arguments = [AROUTER_MODULE_NAME: project.getName()]}}}
}dependencies {implementation 'com.alibaba:arouter-api:x.x.x'annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'...
}

gradle.properties 文件中添加如下行来启用 Jetifier:

主要用于自动将旧版的 Android 库(即基于 Support Library 的库)迁移为 AndroidX 兼容版本。

android.enableJetifier=true

初始化SDK

if (isDebug()) {           // 这两行必须写在init之前,否则这些配置在init过程中将无效ARouter.openLog();     // 打印日志ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化

我们可以在Application中初始化

public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();// 仅在调试模式下开启日志和调试模式if(BuildConfig.DEBUG){ARouter.openLog();ARouter.openDebug();}ARouter.init(this);} 
}

添加注解在目标界面

// 在支持路由的页面上添加注解
// 路径注意至少需有两级,/xx/xx
@Route(path = "/test/second")
public class SecondActivity extends AppCompatActivity {

跳转界面不带参

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void startActivity(View view) {ARouter.getInstance().build("/test/SecondActivity").navigation();}
}

这里跳转放在onCreate里报错:可能是因为ARouter 未初始化完成,初始化放在onCrete里就好了

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 仅在调试模式下开启日志和调试模式if(BuildConfig.DEBUG){ARouter.openLog();ARouter.openDebug();}ARouter.init(getApplication());ARouter.getInstance().build("/test/SecondActivity").navigation();}
}

跳转界面含参

// 1
ARouter.getInstance().build("/test/SecondActivity").withString("key1", "123").withBoolean("key2", false).navigation();// 2
@Route(path = "/test/SecondActivity")
public class SecondActivity extends AppCompatActivity {public String key1;@Autowired(name = "key2")public boolean aBoolean;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);ARouter.getInstance().inject(this);Log.d("SecondActivityTag", key1 + " " + aBoolean);}
}

处理返回结果

如果需要在跳转到新页面并返回结果,可以使用 ARouter.getInstance().build() 方法构建路由请求时,调用 navigation() 方法的重载版本,传入一个 NavigationCallback 回调接口来处理返回结果

ARouter.getInstance().build("/main/selectActivity").navigation(this, new NavigationCallback() {@Overridepublic void onFound(Postcard postcard) {// 找到目标页面}@Overridepublic void onLost(Postcard postcard) {// 找不到目标页面}@Overridepublic void onArrival(Postcard postcard) {// 到达目标页面}@Overridepublic void onInterrupt(Postcard postcard) {// 路由被拦截}});

源码

基本流程

getInstance()

ARouter.getInstance().build("/test/SecondActivity").navigation();

双检锁,获取ARouter类的单例

public static ARouter getInstance() {if (!hasInit) {throw new InitException("ARouter::Init::Invoke init(context) first!");} else {if (instance == null) {synchronized (ARouter.class) {if (instance == null) {instance = new ARouter();}}}return instance;}
}

build()

这里使用了门面模式。外部调用者只需与 ARouter 交互,获取路由对象,不需要了解 _ARouter 内部如何管理单例、如何创建 Postcard 等。

build返回一个Postcard,

// ARouter.java
public Postcard build(String path) {return _ARouter.getInstance().build(path);
}
// _ARouter.java
protected Postcard build(String path) {if (TextUtils.isEmpty(path)) {throw new HandlerException(Consts.TAG + "Parameter is invalid!");} else {// 预处理替换: 有需求来对 path 做统一的预处理就实现 PathReplaceService PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {path = pService.forString(path);}// extractGroup()方法提取path的组名return build(path, extractGroup(path), true);}
}

这里返回new出的一个Postcard对象,包含他的path和组名

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);}
}
  • Postcard 类

Postcard 类继承自 RouteMeta,是路由的实际载体,包含导航需要的额外信息。它不仅继承了 RouteMeta 的基本字段,还添加了与导航操作密切相关的属性。

public final class Postcard extends RouteMeta {private Uri uri;private Object tag;private Bundle mBundle;private int flags = 0; private int timeout = 300; private IProvider provider;     private boolean greenChannel;   private SerializationService serializationService;private Context context;       private String action;          
}

上文创建Postcard对象时会通过set方法设置到父类RouteMeta的属性中

image-20241121210159228

  • RouteMeta 类

RouteMeta 是一个数据模型类,用于描述路由的元信息。该类中的属性用于存储路由目标、路径、分组及相关的附加信息。

public class RouteMeta {private RouteType type;         // 路由类型 (枚举类型,标识不同的路由类型, 例如 ACTIVITY、SERVICE 等)private Element rawType;        // 原始类型 (可能是路由的注解元素,用于生成代码时保留元信息)private Class<?> destination;   // 路由目标 (路由的目标类,例如某个 Activity 或 Fragment)private String path;            // 路由路径 (唯一标识路由的字符串,例如 "/app/home")private String group;           // 路由分组 (用于管理路由分组,例如 "app"、"user")private int priority = -1;      // 路由优先级 (数值越小,优先级越高)private int extra;              // 额外信息 (存储扩展数据,通常用于业务需求)private Map<String, Integer> paramsType;  // 参数类型映射 (参数名与参数类型的映射,例如 {"id": String.class})private String name;            // 路由名称 (可选字段,用于描述路由)
}

navigation()

导航

image-20241121210654863

由上至下调用,然后调用到ARouter的navigation方法

image-20241121210929136

该方法完成了从调用导航到实际路由跳转的逻辑处理

//_ARouter.java
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {// 1.确保 Postcard 能绑定一个有效的 Contextpostcard.setContext(null == context ? mContext : context);try {// 2.根据路由路径完善 Postcard 的信息LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {logger.warning(Consts.TAG, ex.getMessage());// 调试功能if (debuggable()) {runInMainThread(new Runnable() {@Overridepublic void run() {Toast.makeText(mContext, "There's no route matched!\n" +" Path = [" + postcard.getPath() + "]\n" +" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();}});}// 2.1 捕获到异常:Postcard 路径不存在// 存在回调接口,就通知调用 onLost() 方法。if (null != callback) {callback.onLost(postcard);} else {// 不存在回调接口,执行全局降级服务,调用onLost方法,当路由丢失时可以做一些事情。DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}return null;}// 2.2 没捕获到异常,回调onFound方法if (null != callback) {callback.onFound(postcard);}// 3.1 不是绿色通道,拦截器进行处理// 拦截器:扩展,允许开发者在导航过程中插入自定义逻辑,比如权限检查、登录验证或其他操作。// onContinue():继续路由操作。// onInterrupt():终止路由操作,并通知回调接口 onInterrupt()。if (!postcard.isGreenChannel()) {  interceptorService.doInterceptions(postcard, new InterceptorCallback() {@Overridepublic void onContinue(Postcard postcard) {_navigation(postcard, requestCode, callback);}@Overridepublic void onInterrupt(Throwable exception) {if (null != callback) {callback.onInterrupt(postcard);}logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());}});} else {// 如果 isGreenChannel() 返回 true,则跳过拦截器,直接导航。// 开发模式下跳过非必要检查,加速导航return _navigation(postcard, requestCode, callback);}return null;
}

总结:该方法完善了postcard的信息,路径验证,拦截器逻辑

最后调用的_navigation将执行跳转逻辑

_navigation()

private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {final Context currentContext = postcard.getContext();// 根据路由类型switch (postcard.getType()) {// 1.跳转到活动case ACTIVITY:// 通过getDestination()方法拿到目标页面的 Classfinal Intent intent = new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras());// 设置标志位(可选)int flags = postcard.getFlags();if (0 != flags) {intent.setFlags(flags);}// 如果当前上下文不是一个 Activity,则添加 FLAG_ACTIVITY_NEW_TASK,确保能够从非 Activity 环境启动目标页面。if (!(currentContext instanceof Activity)) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}// 设置 ActionsString action = postcard.getAction();if (!TextUtils.isEmpty(action)) {intent.setAction(action);}//  在主线程启动 ActivityrunInMainThread(new Runnable() {@Overridepublic void run() {startActivity(requestCode, currentContext, intent, postcard, callback);}});break;// 想要获取的服务,即IProvider的实现类。case PROVIDER:return postcard.getProvider();// 下面三个都是通过反射创建实例case BOARDCAST:case CONTENT_PROVIDER:case FRAGMENT:// 通过getDestination得到目标类对象Class<?> fragmentMeta = postcard.getDestination();try {// 通过反射构造Object instance = fragmentMeta.getConstructor().newInstance();// 类型判断,适配不同类型的fragmentif (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;
}

Warehouse

我们在navigation方法中调用了LogisticsCenter.completion(postcard);,来完善了postcard的信息

completion里出现了Warehouse,我们看看是什么

image-20241121223437888

Warehouse

用于存储路由表和相关的映射数据结构。它是 ARouter 的“仓库”,负责管理路由信息的加载、存储和查询。

主要职责是作为数据中心,保存路由信息、拦截器、服务等的映射关系。它将这些信息加载到内存中,方便 ARouter 在运行时快速查找目标页面或功能。

// Warehouse.java
class Warehouse {static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>(); static Map<String, RouteMeta> routes = new HashMap<>();static Map<Class, IProvider> providers = new HashMap<>();static Map<String, RouteMeta> providersIndex = new HashMap<>();static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("...");static List<IInterceptor> interceptors = new ArrayList<>();static void clear() {routes.clear();groupsIndex.clear();providers.clear();providersIndex.clear();interceptors.clear();interceptorsIndex.clear();}
}

在 ARouter 中,路由表、拦截器表、服务表分别用来管理路由路径、拦截器以及服务的相关信息,从而实现模块化开发、路径导航、拦截器链、以及服务的统一管理。以下是关于各部分的详细分析:

  1. 路由表

groupsIndex

  • 存储路由组名具体路由组类的映射。通过这种分组方式,可以有效减少路由加载的时间和内存占用。

  • public static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    
    • Key:路由组名(如 "user"),表示属于哪个功能模块。
    • Value:实现了 IRouteGroup 接口的类,用于提供具体的路由信息。
  • 当访问一个路由路径时,ARouter 首先查找该路径所属的组(groupsIndex 中的 Key)。

    通过路由组类(Value)加载组内所有路由信息到 routes

routes

  • 存储完整路由路径到**路由元信息(RouteMeta)**的映射。

  • public static Map<String, RouteMeta> routes = new HashMap<>();
    
    • Key:完整路径(如 /user/profile)。
    • ValueRouteMeta 对象,包含目标页面类、参数、类型等信息。
  • groupsIndex 确定路由组后,通过组加载具体的路由信息到 routes 中。

    最终通过路径快速定位到 RouteMeta

  1. 拦截器表

interceptorsIndex

  • 管理拦截器的优先级和对应的实现类,方便构建拦截器链。

  • public static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new HashMap<>();
    
    • Key:拦截器优先级(Priority),数字越小优先级越高。
    • Value:拦截器类(IInterceptor 的实现类)。
  • 允许开发者在路由跳转前拦截请求、检查参数、处理权限等。

interceptors

  • 缓存所有拦截器的实例。

  • static List<IInterceptor> interceptors = new ArrayList<>();
    
  • 路由跳转时,从 interceptors 依次执行所有拦截器。

  • 开发者可以实现拦截器逻辑,比如登录验证、动态权限申请等。

  1. 服务表

providers

  • 缓存服务实例(IProvider),用于提供功能模块的具体实现。

  • static Map<Class, IProvider> providers = new HashMap<>();
    
    • Key:服务接口的 Class 对象。
    • Value:服务接口的具体实现实例。
  • 在应用中实现全局服务调用。

    例如:网络管理器、日志管理器、用户管理等。

providersIndex

  • 存储服务实现类的元信息,用于动态加载服务。

  • public static Map<String, RouteMeta> providersIndex = new HashMap<>();
    
    • Key:服务类的全类名。
    • ValueRouteMeta 对象,包含服务实现类的信息。
  • 路由初始化时,将服务实现类的信息加载到 providersIndex

    在需要服务时,通过 providersIndex 获取元信息并实例化服务。

Warehouse 的数据是在 LogisticsCenter 类的 init() 方法中被加载的

ARouter初始化

init

ARouter.init()出发

// ARouter.java
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.java
protected static synchronized boolean init(Application application) {mContext = application;//LogisticsCenter.init(mContext, executor);logger.info(Consts.TAG, "ARouter init success!");hasInit = true;mHandler = new Handler(Looper.getMainLooper());return true;
}
// LogisticsCenter.java
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {// 保存上下文和线程池引用。mContext = context; executor = tpe;try {long startInit = System.currentTimeMillis(); // 尝试使用AGP加载路由表loadRouterMap(); if (registerByPlugin) {logger.info(TAG, "Load router map by arouter-auto-register plugin.");} else {Set<String> routerMap; // 路由表集合// 1. 如果是调试模式或是新安装应用,则重建路由表if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {logger.info(TAG, "Run with debug mode or new install, rebuild router map.");// 获取指定包名下的所有类名(编译时生成的所有帮助类)// ROUTE_ROOT_PAKCAGE: "com.alibaba.android.arouter.routes"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 {// 2. 从缓存中加载路由表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>()));}//遍历帮助类,区分是哪种帮助类,然后反射创建帮助类实例后,调用其loadInto方法来填充Warehouse相应的Mapfor (String className : routerMap) {if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {//类名开头:com.alibaba.android.arouter.routes.ARouter$$Root//填充Warehouse.groupsIndex,即所有IRouteGroup实现类的class对象((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {//类名开头:com.alibaba.android.arouter.routes.ARouter$$Interceptors//填充Warehouse.interceptorsIndex,即所有IInterceptor实现类的class对象((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {//类名开头:com.alibaba.android.arouter.routes.ARouter$$Providers//填充Warehouse.providersIndex,即所有provider的RouteMeta((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() + "]");}
}

总结:

  1. 确定路由表的加载方式(插件自动注册(编译时)或手动扫描(运行时)。
  2. 判断是否需要重建路由表(调试模式或版本变化)。
  3. 加载路由表信息到内存(通过反射机制调用生成的类)。
  4. 提供异常处理和性能数据统计。

帮助类

根帮助类

路由组元信息的收集是通过根帮助类

用来实现对 WareHouse.groupsIndex 赋值

static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>(); 
  • 把path第一级相同的所以路由分到同一个组中。

key:组名

value:组帮助类

image-20241123202011347

这里loadInto方法的参数类型就是groupsIndex的类型

// LogisticsCenter.java
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {...for (String className : routerMap) {if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {//类名开头:com.alibaba.android.arouter.routes.ARouter$$Root//填充Warehouse.groupsIndex,即所有IRouteGroup实现类的class对象((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);}...}
}

组帮助类

帮助WareHouse填充Warehouse.routes

 static Map<String, RouteMeta> routes = new HashMap<>();
package com.alibaba.android.arouter.routes;
public class ARouter$$Group$$test implements IRouteGroup {@Overridepublic void loadInto(Map<String, RouteMeta> atlas) {atlas.put("/test/SecondActivity", RouteMeta.build(RouteType.ACTIVITY, SecondActivity.class, "/test/secondactivity", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); put("key2", 0); }}, -1, -2147483648));}
}

可以看到每个路由的目标类class被放在了RouteMeta

completion

/*** 尝试完成 Postcard 的路由信息填充,包括加载动态分组路由和设置目标类。** @param postcard 路由信息的载体,目前只包含 path 和 group 属性*/
public synchronized static void completion(Postcard postcard) {// 检查 Postcard 是否为空if (null == postcard) {throw new NoRouteFoundException(TAG + "No postcard!");}// 尝试通过 path 获取路由元信息RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());if (null == routeMeta) {// 如果未获取到路由元信息,检查是否有该组的帮助类if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");} else {try {// 如果存在该组的帮助类,加载该组的所有路由if (ARouter.debuggable()) {logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));}// 加载分组路由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 以重新获取路由元信息completion(postcard);return;}} else {// 如果获取到路由元信息,将其同步到 Postcard 中postcard.setDestination(routeMeta.getDestination());postcard.setType(routeMeta.getType());postcard.setPriority(routeMeta.getPriority());postcard.setExtra(routeMeta.getExtra());// 如果包含原始 URI,则解析参数并设置到 Postcard 中Uri rawUri = postcard.getUri();if (null != rawUri) {Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);Map<String, Integer> paramsType = routeMeta.getParamsType();if (MapUtils.isNotEmpty(paramsType)) {// 按类型设置参数值,仅处理使用 @Param 注解的参数for (Map.Entry<String, Integer> params : paramsType.entrySet()) {setValue(postcard, params.getValue(), params.getKey(), resultMap.get(params.getKey()));}// 保存需要自动注入的参数名postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));}// 保存原始 URIpostcard.withString(ARouter.RAW_URI, rawUri.toString());}// 根据路由类型进一步处理switch (routeMeta.getType()) {case PROVIDER: // 如果是服务类型的路由// 确认目标类实现了 IProvider 接口Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();IProvider instance = Warehouse.providers.get(providerMeta);if (null == instance) { // 如果服务实例尚未创建try {// 创建服务实例并初始化IProvider 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();       // 跳过拦截器break;case FRAGMENT: // 如果是 Fragment 类型的路由postcard.greenChannel();       // Fragment 也跳过拦截器default:break;}}
}

尝试获取路由元信息 → 检查并加载路由组 → 同步元信息 → 判断目标类并处理

总结

img

10018045-493c8e3b855f4332


参考:

  1. “终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解-腾讯云开发者社区-腾讯云 (tencent.com)
  2. ARouter源码解析(一)-腾讯云开发者社区-腾讯云 (tencent.com)
  3. ARouter/README_CN.md at master · alibaba/ARouter (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62084.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国内首家! 阿里云人工智能平台 PAI 通过 ITU 国际标准测评

近日&#xff0c;阿里云人工智能平台 PAI 顺利通过中国信通院组织的 ITU-T AICP-GA&#xff08;Technical Specification for Artificial Intelligence Cloud Platform&#xff1a;General Architecture&#xff09;国际标准和《智算工程平台能力要求》国内标准一致性测评&…

SpringBoot文件上传之秒传、断点续传、分片上传

一 文件上传的常见场景 在日常开发中&#xff0c;文件上传的场景多种多样。比如&#xff0c;在线教育平台上的视频资源上传&#xff0c;社交平台上的图片分享&#xff0c;以及企业内部的知识文档管理等。这些场景对文件上传的要求也各不相同&#xff0c;有的追求速度&#xff…

力扣 最长回文字串-5

最长回文字串-5 //双指针&#xff0c;暴力解法 class Solution { public:bool is(string s, int l, int r) // 判断是否为回文{while (l < r) {if (s[l] ! s[r]) {return false;}l;r--;}return true;}string longestPalindrome(string s) {int Max 0;//用来判断找出最长字…

【算法】快速求出 n 最低位的 1

Leetcode 2438. 二的幂数组中查询范围内的乘积 先展示算法具体实现 while (n) {int lowbit n & (-n);powers.push_back(lowbit);n ^ lowbit; }这段代码的核心是通过 n & (-n) 计算出 n 的 最低位的 1&#xff08;即最右边的 1&#xff09; -n 是 n 的二进制补码表…

数据抽取平台pydatax使用案例---11个库项目使用

数据抽取平台pydatax&#xff0c;前期项目做过介绍&#xff1a; 1&#xff0c;数据抽取平台pydatax介绍--实现和项目使用 项目2&#xff1a; 客户有9个分公司&#xff0c;用的ERP有9套&#xff0c;有9个库&#xff0c;不同版本&#xff0c;抽取的同一个表字段长度有不一样&…

.NET9 - Swagger平替Scalar详解(四)

书接上回&#xff0c;上一章介绍了Swagger代替品Scalar&#xff0c;在使用中遇到不少问题&#xff0c;今天单独分享一下之前Swagger中常用的功能如何在Scalar中使用。 下面我们将围绕文档版本说明、接口分类、接口描述、参数描述、枚举类型、文件上传、JWT认证等方面详细讲解。…

shiny动态生成颜色选择器并将其用于绘图

在 Shiny 中使用 uiOutput 和 renderUI 动态生成 UI 控件是一种灵活的方法。结合 uiOutput(ns("colorSelectors")) 的用法&#xff0c;可以实现动态生成颜色选择器&#xff0c;并响应用户选择进行绘图或更新显示。 代码 library(shiny) library(colourpicker)# UI …

【单点知识】基于PyTorch进行模型部署

文章目录 0. 前言1. 模型导出1.1 TorchScript1.1.1 使用 torch.jit.trace1.1.2 使用 torch.jit.script 1.2 ONNX1.2.1 导出为 ONNX 格式 1.3 导出后的模型加载1.3.1 加载 TorchScript 模型1.3.2 加载 ONNX 模型 2. 模型优化2.1 模型量化2.2 模型剪枝 3. 服务化部署3.1 Flask 部…

‌Kotlin中的?.和!!主要区别

目录 1、?.和!!介绍 2、使用场景和最佳实践 3、代码示例和解释 1、?.和!!介绍 ‌Kotlin中的?.和!!主要区别在于它们对空指针的处理方式。‌ ‌?.&#xff08;安全调用操作符&#xff09;‌&#xff1a;当变量可能为null时&#xff0c;使用?.可以安全地调用其方法或属性…

java基础知识(常用类)

目录 一、包装类(Wrapper) (1)包装类与基本数据的转换 (2)包装类与String类型的转换 (3)Integer类和Character类常用的方法 二、String类 (1)String类介绍 1)String 对象用于保存字符串,也就是一组字符序列 2)字符串常量对象是用双引号括起的字符序列。例如:&quo…

《Hello YOLOv8从入门到精通》5,颈部网络(Neck)结构、核心源码和参数调优

YOLOv8的颈部网络&#xff08;Neck&#xff09;是目标检测模型中的关键组成部分&#xff0c;它位于骨干网络&#xff08;Backbone&#xff09;和头部网络&#xff08;Head&#xff09;之间&#xff0c;主要负责进行特征融合和增强。 在YOLOv8中&#xff0c;颈部网络采用了先进…

C#里怎么样实现单向链表?

C#里怎么样实现单向链表? 数据结构,是程序基本表示方法。 不同的数据结构,就需要采用不同的算法。 在软件开发中,使用到的链表还是比较多的。不过,目前C#语言,基本上都类库, 所以需要自己创建链表的机会,基本不存在了。 但是作为理解原理,还是学习一下吧。 下面的例…

Servlet细节

目录 1 Servlet 是否符合线程安全&#xff1f; 2 Servlet对象的创建时间&#xff1f; 3 Servlet 绑定url 的写法 3.1 一个Servlet 可以绑定多个url 3.2 在web.xml 配置文件中 url-pattern写法 1 Servlet 是否符合线程安全&#xff1f; 答案&#xff1a;不安全 判断一个线程…

对比三种UI交互界面的方案

在嵌入式系统的显示应用领域&#xff0c;如何高效、稳定地驱动TFT LCD显示屏至关重要。当下主流方案有三种&#xff1a; 单片机控制芯片屏 &#xff0c;常见的是瑞佑系列芯片单片机串口屏&#xff0c;常见迪文和大彩单片机内建LCD驱动&#xff0c;常见比如ST32F429等 这三种各…

w~视觉~3D~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/12538137 #SIF3D 通过两种创新的注意力机制——三元意图感知注意力&#xff08;TIA&#xff09;和场景语义一致性感知注意力&#xff08;SCA&#xff09;——来识别场景中的显著点云&#xff0c;并辅助运动轨迹和姿态的预测…

fastjson不出网打法—BCEL链

前言 众所周知fastjson公开的就三条链&#xff0c;一个是TemplatesImpl链&#xff0c;但是要求太苛刻了&#xff0c;JNDI的话需要服务器出网才行&#xff0c;BCEL链就是专门应对不出网的情况。 实验环境 fastjson1.2.4 jdk8u91 dbcp 9.0.20 什么是BCEL BCEL的全名应该是…

GitLab使用操作v1.0

1.前置条件 Gitlab 项目地址&#xff1a;http://******/req Gitlab账户信息&#xff1a;例如 001/******自己的分支名称&#xff1a;例如 001-master&#xff08;注&#xff1a;master只有项目创建者有权限更新&#xff0c;我们只能更新自己分支&#xff0c;然后创建合并请求&…

MATLAB GUI设计(基础)

一、目的和要求 1、熟悉和掌握MATLAB GUI的基本控件的使用及属性设置。 2、熟悉和掌握通过GUIDE创建MATLAB GUI的方法。 3、熟悉和掌握MATLAB GUI的菜单、对话框及文件管理框的设计。 4、熟悉和掌握MATLAB GUI的M文件编写。 5、了解通过程序创建MATLAB GUI的方法。 二、内…

RabbitMQ简单应用

概念 RabbitMQ 是一种流行的开源消息代理&#xff08;Message Broker&#xff09;软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP - Advanced Message Queuing Protocol&#xff09;。RabbitMQ 通过高效的消息传递机制&#xff0c;主要应用于分布式系统中解耦应用…

第 36 章 - Go语言 服务网格

服务网格&#xff08;Service Mesh&#xff09;是一种管理服务间通信的方法&#xff0c;它允许开发人员对服务之间的交互进行抽象化处理。通过在基础设施层面上实现这一点&#xff0c;服务网格可以帮助解决微服务架构中常见的复杂性和挑战&#xff0c;比如服务发现、负载均衡、…