# 路由架构梳理 站点:答源(https://www.dandroid.cn/) 原文:https://www.dandroid.cn/archives/20293 Canonical:https://www.dandroid.cn/archives/20293 作者:admin 发布日期:2023-09-13 最后更新:2023-09-13 16:07 分类:教程 内容类型:post 说明:本页是原文的纯文本镜像,供大模型与检索器完整读取;不含导航、广告、付费框。引用请以上方「原文」链接为准。 ## 正文 本文整理一下WMRouter的基本路由逻辑,并剖析相关路由类的设计。 基本元素 先来简单理解一下WMRouter路由过程中的几个基本元素 : UriRequest : 用于封装一个路由请求 UriInterceptor : 代表一个拦截器,可以对一个UriRequest进行拦截,通过UriCallback来告诉拦截结果。 UriCallback : Uri处理的一个统一回调。 回调它的onNext方法代表继续处理、回调它的onComplete代表这次路由请求处理完毕。 UriHandler (定义基本的路由逻辑) WMRouter中,对于每一个或每一类Uri都会有一个UriHandler来处理,UriHandler定义了处理一个Uri的基本逻辑。 public abstract class UriHandler { //拦截器列表 protected ChainedInterceptor mInterceptor; //添加拦截器 public UriHandler addInterceptor(@NonNull UriInterceptor interceptor) { .... } //Uri处理的基本流程, public void handle(@NonNull final UriRequest request, @NonNull final UriCallback callback) { ... } // 是否要处理给定的URI protected abstract boolean shouldHandle(@NonNull UriRequest request); //子类需要重写的处理逻辑 protected abstract void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback); } UriHandler在对一个Uri处理时,会调用handle方法,这个方法定义了一个UriRequest被处理的基本过程。 //处理URI。通常不需要覆写本方法。 public void handle(@NonNull final UriRequest request, @NonNull final UriCallback callback) { if (shouldHandle(request)) { //是否可以处理这个 uri request if (mInterceptor != null && !request.isSkipInterceptors()) { mInterceptor.intercept(request, new UriCallback() { @Override public void onNext() { handleInternal(request, callback); } @Override public void onComplete(int result) { callback.onComplete(result); } }); } else { handleInternal(request, callback); } } else { callback.onNext(); } } OK,在WMRouter中一个uri被处理的基本逻辑可用用下图表示 : 所以,定义一个基本的处理Uri的类应继承自UriHandler,并复写handleInternal方法。 ChainedInterceptor 上面源码你会发现UriHandler中的拦截器类型是ChainedInterceptor,并不是UriInterceptor。那 ChainedInterceptor 是一个什么样的拦截器呢 ?: public class ChainedInterceptor implements UriInterceptor{ private final List mInterceptors = new LinkedList<>(); } 即也是一个拦截器, 不过它含有一个拦截器列表。那么这个拦截器是如何工作的呢?看一下它的intercept()方法 : public void intercept(@NonNull UriRequest request, @NonNull UriCallback callback) { next(mInterceptors.iterator(), request, callback); } private void next(@NonNull final Iterator iterator, @NonNull final UriRequest request, @NonNull final UriCallback callback) { if (iterator.hasNext()) { //对于链上的每一个 interceptor 都要调用一遍它的 intercept 方法 iterator.next().intercept(request, new UriCallback() { @Override public void onNext() { next(iterator, request, callback); } @Override public void onComplete(int resultCode) { callback.onComplete(resultCode); } }); } else { callback.onNext(); } } 即,依次遍历每一个UriInterceptor,调用其intercept方法。 ChainedHandler 概念和ChainedInterceptor类似,它其实也是一个UriHandler, 也含有一个UriHandler列表,在其handleInternal方法中,会依次调用UriHandler.handle()。 @Override protected void handleInternal(@NonNull final UriRequest request, @NonNull final UriCallback callback) { next(mHandlers.iterator(), request, callback); } private void next(@NonNull final Iterator iterator, @NonNull final UriRequest request, @NonNull final UriCallback callback) { if (iterator.hasNext()) { UriHandler t = iterator.next(); t.handle(request, new UriCallback() { @Override public void onNext() { next(iterator, request, callback); } @Override public void onComplete(int resultCode) { callback.onComplete(resultCode); } }); } else { callback.onNext(); } } 上面我们了解了WMRouter中路由的基本组成元素UriRequest、UriHandler、UriInterceptor、ChainedHandler、ChainedInterceptor。那WMRouter是如何使用这些基本元素来搭建一个路由框架的呢 ? RootUriHandler (路由的起点) 它继承自ChainedHandler,提供startUri(UriRequest)并传入RootUriCallback来作为一次路由的起点: public void startUri(@NonNull UriRequest request) { ... handle(request, new RootUriCallback(request)); } protected class RootUriCallback implements UriCallback { private final UriRequest mRequest; ... @Override public void onNext() { onComplete(CODE_NOT_FOUND); } @Override public void onComplete(int resultCode) { switch (resultCode) { case CODE_REDIRECT: // 重定向,重新跳转 startUri(mRequest); break; case CODE_SUCCESS: mRequest.putField(UriRequest.FIELD_RESULT_CODE, resultCode); onSuccess(mRequest); //全局路由成功回调 break; default: mRequest.putField(UriRequest.FIELD_RESULT_CODE, resultCode); onError(mRequest, resultCode); //全局路由失败回调 break; } } } 在WMRouter中路由的起点UriHandler为DefaultRootUriHandler,它继承自RootUriHandler, 这个UriHandler在起始时添加了下面4个子UriHandler : public DefaultRootUriHandler(Context context,@Nullable String defaultScheme, @Nullable String defaultHost) { addChildHandler(createPageAnnotationHandler(), 300); // 处理@RouterPage注解定义的内部页面跳转 addChildHandler(createUriAnnotationHandler(defaultScheme, defaultHost), 200); //处理@RouterUri注解定义的URI跳转, addChildHandler(createRegexAnnotationHandler(), 100); //处理@RouterRegex注解定义的uri addChildHandler(new StartUriHandler(), -100); //支持Android原生隐士跳转 } 这几个子UriHandler当然也是继承自UriHandler, 这里每一个子UriHandler都是一个ChainedHandler,即都会含有很多UriHandler。 那如何开始一次路由呢? 即使用 DefaultRootUriHandler.startUri(UriRequest)。 DefaultRootUriHandler就会把这个UriRequest依次分发给其子UriHandler。 一旦有一个UriHandler处理或者这个UriInterceptor拦截。那么这次路由请求就结束了。 所以整个路由框架大体路由架构如下图所示 : 路由节点的动态生成 UriAnnotationHandler的构成 这个类主要有两个功能: 继承自UrlHandler,内部包含许多PathHandler,可以处理多个(Scheme+Host)的Uri。 加载@RouterUri生成的UrlHandler,并添加到其对应的PathHandler中。作为路由节点。 在弄清楚UriAnnotationHandler的构成之前,我们先来看一下什么是PathHandler PathHandler 这个类也继承自UriHandler,内部含有一个UriHandler的map,是用来处理指定某一类(固定path前缀)的Uri的: public class PathHandler extends UriHandler { private final CaseInsensitiveNonNullMap mMap = new CaseInsensitiveNonNullMap<>(); //其实就是类型的map ... } 回顾一下一个uri的组成: Scheme + //: + Host + / + Path + (?) + QueryParams 其实浏览源码,我并没有看到太多设置path prefix的使用,因此这里简单的理解为PathHandler就是UriHandler的集合,可以通过register()来注册一个UriHandler, 这个UriHandler就会以path为key, 它(UriHandler)为value,放入map中: //注册一个 UriHandler, key为路由的path public void register(String path, Object target, boolean exported, UriInterceptor... interceptors) { if (!TextUtils.isEmpty(path)) { path = RouterUtils.appendSlash(path); // 添加 path与host的分割斜线 `/` UriHandler UriHandler = UriTargetTools.parse(target, exported, interceptors); mMap.put(path, UriHandler); } } //UriTargetTools public static UriHandler parse(Object target, boolean exported,UriInterceptor... interceptors) { UriHandler handler = toHandler(target); ...添加拦截器 return handler; } private static UriHandler toHandler(Object target) { if (target instanceof UriHandler) { return (UriHandler) target; } else if (target instanceof String) { return new ActivityClassNameHandler((String) target); } else if (target instanceof Class && isValidActivityClass((Class) target)) { return new ActivityHandler((Class) target); } else { return null; } } 根据toHandler()可以知道在注册一个UriHandler是我们可以直接传递一个页面的全类名、UriHandler、Activity的class实例。UriTargetTools.parse()会解析,并生成对应的UriHandler实例。 继续看一下PathHandler这个类的handlerInternal(),我们前面已经知道这个方法会在UriHandler.handle()方法中调用: @Override protected void handleInternal(@NonNull final UriRequest request, @NonNull final UriCallback callback) { UriHandler h = mMap.get(request.getUri().getPath()); if (h != null) { h.handle(request, new UriCallback() { @Override public void onNext() { handleByDefault(request, callback); //page note found } @Override public void onComplete(int resultCode) { callback.onComplete(resultCode); } }); } else { handleByDefault(request, callback); } } 即根据UriRequest的path获取对应的UriHandler,处理这个uri。 继续看UriAnnotationHandler。 这个类也有一个map,其类型为Map。 key是Scheme://Host。它也提供一个register()方法来添加PathHandler : public void register(String scheme, String host, String path, Object handler, boolean exported, UriInterceptor... interceptors) { String schemeHost = RouterUtils.schemeHost(scheme, host); PathHandler pathHandler = mMap.get(schemeHost); if (pathHandler == null) { pathHandler = createPathHandler(); mMap.put(schemeHost, pathHandler); } pathHandler.register(path, handler, exported, interceptors); } 很简单,即把handler放到对应key(scheme+host)的 PathHandler中,如果PathHandler不存在则创建。 UriAnnotationHandler.handleInternal方法也很简单: @Override protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) { PathHandler pathHandler = getChild(request); if (pathHandler != null) pathHandler.handle(request, callback); else callback.onNext(); } 即根据UriRequest的 scheme+host获取对应的PathHandler,交由PathHandler处理,而PathHandler其实就是根据Uri的path,获取对应的UriHandler来处理这个uri ok上面我们大致知道了UriAnnotationHandler的组成,以及对于一个UriRequest它是如何处理的。 那么它的构成基础UriHandler是怎么注册的呢?即如何添加到PathHandler中的呢? 路由节点的动态生成 上面分析后,我们知道UriAnnotationHandler提供了register方法来向其中注册uri。它会根据uri来生成对应的UriHandler。那么这些注册代码在哪里?怎么生成的呢? 我们先看一下如何在WMRouter中定义一个路由节点(即,如何给定一个Url,然后跳转到我们想要跳转的page)。在WMRouter中我们可以通过注解来定义可被路由的Page: @RouterUri(scheme = "test", host = "channel1", path = "test_a") public class TestAActivity extends BaseActivity 我们在代码中可以使用 Router.startUri(context, "test://channel1/test_a"), 跳转到我们定义的这个Activity。其实Router.startUri()的具体实现就是调用DefaultRootUriHandler方法来开始整个路由节点的遍历: public static void startUri(Context context, String uri) { getRootHandler().startUri(new UriRequest(context, uri)); } 按照我们目前对WMRouter的理解,应该有一个UrlHandler可以处理这个uri。那么这个UrlHandler是怎么来的呢?即是什么时候注册到DefaultRootUriHandler中的呢?。其实WMRouter会在编译时它编译时解析@RouterUri注解,并生成一些代码: public class UriAnnotationInit_xxx implements IUriAnnotationInit { public void init(UriAnnotationHandler handler) { handler.register("test", "channel1", "/test_a", "com.xxx.TestAActivity", false); } } 即在编译时,WMRouter生成了把@RouterUri注解的Activity与其对应的uri注册到UrlAnnotationHandler的代码。这些代码会在UrlAnnotationHandler初始化时调用。即调用了UrlAnnotationHandler.register()。 这样UrlAnnotationHandler中就会按照我们前面的分析,生成处理这个uri的UriHandler。这样我们在调用Router.startUri(),自然就可以导航到目标界面。 这里我们先不讨论,生成的代码是如何注册到运行时RootUriHandler的UriAnnotationHandler实例中的,我们先来看一下这个代码是如何生成的? 要了解这段代码如何生成我们需要先了解一下: 注册处理器: https://blog.csdn.net/jeasonlzy/article/details/74273851 javaopet: https://blog.csdn.net/qq_18242391/article/details/77018155 使用上面这两个工具就可以生成上面的注册代码。因此,这两个技术就不在细看,不过你需要了解一下,不然接下来的内容不好理解: 动态扫描注解,生成UriHandler注册代码 我们直接来看一下处理@RouterUri的注解处理器UriAnnotationProcessor的主要处理逻辑: @AutoService(Processor.class) @SupportedSourceVersion(SourceVersion.RELEASE_7) public class UriAnnotationProcessor extends BaseProcessor { @Override public boolean process(Set annotations, RoundEnvironment env) { CodeBlock.Builder builder = CodeBlock.builder(); String hash = null; for (Element element : env.getElementsAnnotatedWith(RouterUri.class)) { Symbol.ClassSymbol cls = (Symbol.ClassSymbol) element; RouterUri uri = cls.getAnnotation(RouterUri.class); if (hash == null) hash = hash(cls.className()); CodeBlock handler = buildHandler(isActivity, cls); CodeBlock interceptors = buildInterceptors(getInterceptors(uri)); // scheme, host, path, handler, exported, interceptors String[] pathList = uri.path(); for (String path : pathList) { builder.addStatement("handler.register($S, $S, $S, $L, $L$L)", uri.scheme(), uri.host(), path, handler, uri.exported(), interceptors); } } buildHandlerInitClass(builder.build(), "UriAnnotationInit" + Const.SPLITTER + hash, Const.URI_ANNOTATION_HANDLER_CLASS, Const.URI_ANNOTATION_INIT_CLASS); return true; } } 大致逻辑是依次处理每一个@RouterUri注解scheme, host, path, handler, exported, interceptors, 并利用这些参数生成register方法的代码: public class UriAnnotationInit_xxx implements IUriAnnotationInit { public void init(UriAnnotationHandler handler) { handler.register("", "", "/show_toast_handler", new ShowToastHandler(), false); handler.register("", "", "/advanced_demo", "com.sankuai.waimai.router.demo.advanced.AdvancedDemoActivity", false); ..... } } 我们可以大致画一下 @RouterUri、UriAnnotationHandler、UriAnnotationProcessor之间的关系: ok,这一节我们知道了@RouterUri标注的页面会生成注册到UriAnnotationHandler中的代码。那这些代码在什么时候调用呢? 我们在下一篇文章再看 路由节点的加载 先了解一下ServiceLoader这个概念。WMRouter中的ServiceLoader类似于java spi ServiceLoader 它的基本功能是: 保存接口与实现类的对应关系。 这个关系是一对多。 可以实例化一个实现类,返回给调用方使用。 那在WMRouter中,SerciceLoader保存的接口与实现类的关系是哪些呢? 我们看一下ServiceLoader的初始化方法: void doInit() { Class.forName(“com.sankuai.waimai.router.generated.ServiceLoaderInit”).getMethod("init").invoke(null); } 即初始化的时候反射调用了ServiceLoaderInit.init()方法。我全局搜索了一下这个类并没有发现它的声明。 最后发现这个类是使用Gradle Transform API和ams库动态生成的。 接下来我们就来研究一下这个类是怎么生成的,先来看一下WMRouter的gradle transform插件是如何生成ServiceLoaderInit这个类的。 WMRouterPlugin 官方是这样描述它的作用的 : 将注解生成器生成的初始化类汇总到ServiceLoader.init,运行时直接调用ServiceLoader.init。 从而完成SerciceLoader的初始化。 这里我大致描述一下这个插件的工作逻辑: 扫描编译生成的class文件夹或者jar包的指定目录 : com/sankuai/waimai/router/generated/service, 收集目录下的类并保存起来 (这个类其实就是ServiceInit_xxx1这种类) 使用asm生成ServiceLoaderInit类class文件,这个class文件调用前面扫描到的类的init方法。 即最终产生如下代码: public class ServiceLoaderInit { public static void init() { ServiceInit_xxx1.init(); ServiceInit_xxx2.init(); } } 到这里就有疑问了,从开始分析到现在我们并没有看到ServiceInit_xxx1这种类是如何生成的呢。那它是在哪里生成的呢? ServiceInit_xx的生成 在上一篇文章已经了解到UriAnnotationProcessor在编译时会扫描@RouterUri,并且会生成UriAnnotationInit_xx1这种类,UriAnnotationInit_xx1.init方法就是接收一个UriAnnotationHandler实例,然后调用它的register方法。 其实UriAnnotationProcessor在扫描@RouterUri生成UriAnnotationInit_xx1类的同时,还会生成一个类,就是ServiceInit_xx: //UriAnnotationProcessor.java public void buildHandlerInitClass(CodeBlock code, String genClassName, String handlerClassName, String interfaceName) { .... // 生成 UriAnnotationInit_xx1 代码 String fullImplName = Const.GEN_PKG + Const.DOT + genClassName; String className = "ServiceInit" + Const.SPLITTER + hash(genClassName); new ServiceInitClassBuilder(className) .putDirectly(interfaceName, fullImplName, fullImplName, false) .build(); } 我们看一下ServiceInitClassBuilder的putDirectly和build方法: public class ServiceInitClassBuilder { ... public ServiceInitClassBuilder putDirectly(String interfaceName, String key, String implementName, boolean singleton) { builder.addStatement("$T.put($T.class, $S, $L.class, $L)", serviceLoaderClass, className(interfaceName), key, implementName, singleton); return this; } public void build() { MethodSpec methodSpec = MethodSpec.methodBuilder(Const.INIT_METHOD) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(TypeName.VOID) .addCode(this.builder.build()) .build(); TypeSpec typeSpec = TypeSpec.classBuilder(this.className) .addModifiers(Modifier.PUBLIC) .addMethod(methodSpec) .build(); JavaFile.builder(“com.sankuai.waimai.router.generated.service”, typeSpec) .build() .writeTo(filer); } 其实就是会把下面代码生成到com/sankuai/waimai/router/generated/service文件夹下: public class ServiceInit_xx1 { public static void init() { ServiceLoader.put(IUriAnnotationInit.class, "com.xxx.UriAnnotationInit_xx1", com.xx.UriAnnotationInit_xx1.class, false); } } 可以看到 ServiceInit_xx1.init的作用就是把接口与实现类的关系保存到ServiceLoader中。 WMRouter的transform插件会扫描com/sankuai/waimai/router/generated/service下的类。即会扫描到ServiceInit_xx1这个类,然后按照刚开始所说的生成调用其init()的代码: public class ServiceLoaderInit { public static void init() { ServiceInit_xxx1.init(); ServiceInit_xxx2.init(); } } 综上所述,ServiceLoaderInit.init被调用后,SerciceLoader中就保存了IUriAnnotationInit的接口实现类UriAnnotationInit_xx1。 接下来的问题就是IUriAnnotationInit的实现类UriAnnotationInit_xx1的init方法在什么时候调用呢 ? UriAnnotationInit_xx1.init的调用时机 其实UriAnnotationInit_xx1.init就是为了把前面经过UriAnnotationProcessor生成的路由节点信息注册到UriAnnotationHandler中。我们来看一下UriAnnotationHandler的初始化方法: protected void initAnnotationConfig() { RouterComponents.loadAnnotation(this, IUriAnnotationInit.class); } 上面的代码最终会调用到这里: List> services = ServiceLoader.load(clazz).getAll(); for (AnnotationInit service : services) { service.init(handler); } 即会通过SerciceLoader来获取IUriAnnotationInit的实现类,并调用其init方法。 前面我们已经分析过了SerciceLoader在初始化时,就已经把IUriAnnotationInit与其实现类的关系保存起来了。所以上面的service.init(handler)实际上就是调用下面的代码 //IUriAnnotationInit的实现类 public class UriAnnotationInit_xx1 implements IUriAnnotationInit { public void init(UriAnnotationHandler handler) { handler.register("", "", "/jump_activity_1", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false); } 结合我们前面所了解的,这样UriAnnotationHandler就生成了用于处理被@RouterUri标记的页面的UriHandlder。 为了便于理解,我们用下面这张图总结一下上面的过程: ServiceLoader中更强大的功能 其实上面利用ServiceLoader来加载一个接口的实现类这个功能,WMRouter这个框架已经把它单独抽取出来了。即利用SerciceLoader可以跨模块加载一个接口的实现类。我们看一下怎么使用 @RouterService java 中的spi机制需要我们在 META-INF/services规范好接口与实现类的关系,WMRouter中提供@RouterService,来简化了这个操作。举个例子 : 比如在一个项目中有3个库: interface、lib1、lib2 //定义在interface库中 public abstract class LibraryModule { public abstract String getModuleName(); } //定义在lib1中 @RouterService(interfaces = LibraryModule.class) public class LibraryModule1 extends LibraryModule { } //定义在lib2 @RouterService(interfaces = LibraryModule.class) public class LibraryModule2 extends LibraryModule { } WMRouter中有一个ServiceAnnotationProcessor负责处理RouterService注解,它会把标记了这个注解的类,生成ServiceInit_xx, 即 public class ServiceInit_f3649d9f5ff15a62b844e64ca8434259 { public static void init() { ServiceLoader.put(IUriAnnotationInit.class, "xxx",xxx.class, false); } } 这样再由WMRouter的插件转换生成 ServiceLoaderInit.init()中的调用代码。就达到在运行时把LibraryModule的实现注入到SerciceLoader中,从而我们可以获得不同库的实现。 到这里我们已经大体剖析完WMRouter的工作原理,下一篇文章我们举一个实例来分析一下这个框架怎么使用: 页面路由实例分析 Activity的路由 首先我们使用@RouterUri标记一个Activity可被路由: @RouterUri(path = {DemoConstant.JUMP_ACTIVITY_1, DemoConstant.JUMP_ACTIVITY_2}) public class TestBasicActivity extends BaseActivity {} 在指定路由界面时,我们可以不指定scheme、host,直接指定path即可。这样指定后我们直接 Router.startUri(DemoConstant.JUMP_ACTIVITY_1),就可以打开这个界面,下面我们就根据我们前面对于源码的分析,来看一下这个具体是怎么完成的: 首先,按照WMRouter的设计,肯定会生成一个UriHandler来处理这个uri,那是由哪个UriHandler来处理呢? 按照我们前面的分析@RouterUri标记的page,会被UriAnnotationProcessor扫描,并在运行时动态注册到UriAnnotationHandler中: handler.register("", "", "/jump_activity_1", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false); handler.register("", "", "/jump_activity_2", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false); UriAnnotationHandler的register方法,按照前面的分析,其实是调用PathHandler的register: public void register(String path, Object target, boolean exported, UriInterceptor... interceptors) { if (!TextUtils.isEmpty(path)) { path = RouterUtils.appendSlash(path); UriHandler parse = UriTargetTools.parse(target, exported, interceptors); UriHandler prev = mMap.put(path, parse); } } public static UriHandler parse(Object target, boolean exported,UriInterceptor... interceptors) { UriHandler handler = toHandler(target); ...... return handler; } private static UriHandler toHandler(Object target) { if (target instanceof UriHandler) { return (UriHandler) target; } else if (target instanceof String) { return new ActivityClassNameHandler((String) target); } else if (target instanceof Class && isValidActivityClass((Class) target)) { //noinspection unchecked return new ActivityHandler((Class) target); } else { return null; } } 因此我们可以确定处理Router.startUri(DemoConstant.JUMP_ACTIVITY_1)的UriHandler是ActivityClassNameHandler,我们来看一下这个类: ActivityClassNameHandler 我们来看一下它的定义: public class ActivityClassNameHandler extends AbsActivityHandler { @NonNull private final String mClassName; public ActivityClassNameHandler(@NonNull String className) { mClassName = className; } @Override protected Intent createIntent(@NonNull UriRequest request) { return new Intent().setClassName(request.getContext(), mClassName); } } 这个类继承自AbsActivityHandler, 重写了父类的createIntent(), 就是返回了一个设置了类名的intent。 public abstract class AbsActivityHandler extends UriHandler { ..... protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) { Intent intent = createIntent(request); if (intent == null || intent.getComponent() == null) { callback.onComplete(UriResult.CODE_ERROR); return; } intent.setData(request.getUri()); UriSourceTools.setIntentSource(intent, request); request.putFieldIfAbsent(ActivityLauncher.FIELD_LIMIT_PACKAGE, limitPackage()); // 启动Activity int resultCode = RouterComponents.startActivity(request, intent); callback.onComplete(resultCode); } //是否只启动当前APP中的Activity protected boolean limitPackage() { return true; } @NonNull protected abstract Intent createIntent(@NonNull UriRequest request); ..... } 可以看到在创建好intent后,真正的Activity的启动时委派给RouterComponents.startActivity(request, intent)。其实最终启动Activity是调用DefaultActivityLauncher.startActivity(UriRequest, context) 在这个方法中主要做了一下事情: 取出UriRequest中的一些信息,设置到intent中 优先启动APP内的界面。即在intent中设置自己的package APP内启动失败,如果允许启动APP外的界面,则清空package,再次尝试启动 启动时如果设置有动画参数,则添加上overridePendingTransition 拦截器的使用 我们这里就简单的看一下官方demo中对拦截器的使用 : @RouterUri(path = DemoConstant.ACCOUNT_WITH_LOGIN_INTERCEPTOR, interceptors = LoginInterceptor.class) public class UserAccountActivity extends BaseActivity {} public class LoginInterceptor implements UriInterceptor { @Override public void intercept(@NonNull UriRequest request, @NonNull final UriCallback callback) { final IAccountService accountService = DemoServiceManager.getAccountService(); if (accountService.isLogin()) { callback.onNext(); } else { Toast.makeText(request.getContext(), "请先登录~", Toast.LENGTH_SHORT).show(); accountService.registerObserver(new IAccountService.Observer() { @Override public void onLoginSuccess() { accountService.unregisterObserver(this); callback.onNext(); } .... }); DemoServiceManager.getAccountService().startLogin(request.getContext()); } } } LoginInterceptor会在UserAccountActivity打开之前调用。监听登录状态,登录成功后则跳转目标界面。源码原理前面其实已经看过了,这里就不仔细看了。 --- 由 答源 DAN 底座 1.4.1 生成 · 2026-11-13T18:08:02+00:00