本文整理一下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<UriInterceptor> mInterceptors = new LinkedList<>();
}
即也是一个拦截器, 不过它含有一个拦截器列表。那么这个拦截器是如何工作的呢?看一下它的intercept()
方法 :
public void intercept(@NonNull UriRequest request, @NonNull UriCallback callback) {
next(mInterceptors.iterator(), request, callback);
}
private void next(@NonNull final Iterator<UriInterceptor> 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<UriHandler> 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<UriHandler> mMap = new CaseInsensitiveNonNullMap<>(); //其实就是<String, UriHandler>类型的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<? extends Activity>) 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<? extends TypeElement> 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<? extends AnnotationInit<T>> services = ServiceLoader.load(clazz).getAll();
for (AnnotationInit<T> 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<? extends Activity>) 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
打开之前调用。监听登录状态,登录成功后则跳转目标界面。源码原理前面其实已经看过了,这里就不仔细看了。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/20293,转载请注明出处。
评论0