本次阅读 WMRouter 源码,主要为了弄清楚一下两个问题:
路由的注册
框架如何将我们配置的路由扫描注册并集中管理
路由过程
通过 Router.startUri 如何实现一次路由
// 创建RootHandler
DefaultRootUriHandler rootHandler = new DefaultRootUriHandler(context);
// 初始化
Router.init(rootHandler);
路由过程
1、路由处理器 & 路由注册对某一类的Uri进行处理。提供 shouldHandle 抽象方法供子类重写来判断自己能否处理当前 UriRequest;提供
handleInternal 抽象方法供子类实现具体的处理逻辑。UriHandle 自身提供了 handle 方法,规定了所有 Handler 的基本逻辑:首先调用 shouldHandle 方法判断当前 Handler 是否需要处理;接着判断当前 Handler 是否配置了拦截器,如果有拦截器先交给拦截器处理,否则直接调用 handleInternal 进行处理。
public void handle(@NonNull final UriRequest request, @NonNull final UriCallback callback) {
if (shouldHandle(request)) {
Debugger.i("%s: handle request %s", this, 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 {
Debugger.i("%s: ignore request %s", this, request);
callback.onNext();
}
}
在 Appliction 中注册的默认的根路由处理器,从上面提供的图中也可以看出每次路由的时候最先被 DefaultRootUriHandler处理。
继承 PathHandler(继承 UriHandler)
shouldHandle
handle 方法,复写的 handle 方法,调用 ensureInit 进行初始化,后续逻辑仍然是 UriHandler中的handle的逻辑
handlerInteral
public static final String SCHEME = "wm_router";
public static final String HOST = "page";
public static final String SCHEME_HOST = RouterUtils.schemeHost(SCHEME, HOST);
@Override
protected boolean shouldHandle(@NonNull UriRequest request) {
return SCHEME_HOST.matches(request.schemeHost());
}
@Override
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
private final LazyInitHelper mInitHelper = new LazyInitHelper("PageAnnotationHandler") {
@Override
protected void doInit() {
initAnnotationConfig();
}
};
// 获取 IPageAnnotationInit 的所有实现类 (Apt生成的)
// 生成的 PageAnnotationInit_XXX 类型
protected void initAnnotationConfig() {
RouterComponents.loadAnnotation(this, IPageAnnotationInit.class);
}
public static void loadAnnotation(T handler, Class extends AnnotationInit> initClass) {
sAnnotationLoader.load(handler, initClass);
}
// sAnnotationLoader 对应的类
public class DefaultAnnotationLoader implements AnnotationLoader {
public static final AnnotationLoader INSTANCE = new DefaultAnnotationLoader();
@Override
public void load(T handler,
Class extends AnnotationInit> initClass) {
// ServiceLoader:获取对应接口的所有实现类
List extends AnnotationInit> services = Router.getAllServices(initClass);
// 调用对应的 Init 方法
for (AnnotationInit service : services) {
service.init(handler);
}
}
}
public class PageAnnotationInit_bfd2eeb94778305f7d7586fccf7b2630 implements IPageAnnotationInit {
public void init(PageAnnotationHandler handler) {
handler.register("/fragment/kroom/feed", new FragmentTransactionHandler("com.netease.cloudmusic.singroom.feed.ui.fragments.SingRoomFeedFragment"));
}
}
PathHandler
根据path分发URI给子节点,支持注册的子节点包括ActivityClassName, ActivityClass, UriHandler (官方注释)
UriAnnotationHandler
StartUriHandler
实现和 PageAnnotationHandler 类似,支持不同的 scheme,内部构造了一个 PathHandler 来完成注册。和 PageAnnotationHandler 不同的是,PageAnnotationHandler 本身就是一个 PathHandler 类型。
public static UriHandler parse(Object target, int priority, Map params,
Class extends UriInterceptor>... interceptors) {
UriHandler handler = toHandler(target, params);
if (handler != null) {
if (UriSourceTools.FROM_INTERNAL == priority) {
handler.addInterceptor(SourceInternalInterceptor.class);
} else if (UriSourceTools.FROM_EXTERNAL == priority) {
handler.addInterceptor(SourceExternalInterceptor.class);
} else if (UriSourceTools.FROM_WEBVIEW == priority) {
handler.addInterceptor(SourceWebViewInterceptor.class);
}
handler.addInterceptors(interceptors);
}
return handler;
}
private static UriHandler toHandler(Object target, Map params) {
if (target instanceof UriHandler) {
return (UriHandler) target;
} else if (target instanceof String) {
// 一般代码中生成的注册方法都是对应这个case
return new ActivityClassNameHandler((String) target, params);
} else if (target instanceof Class) {
Class clazz = (Class) target;
if (isValidActivityClass(clazz)) {
//noinspection unchecked
return new ActivityHandler((Class extends Activity>) target, params);
} else if (isValidUriHandlerClass(clazz)) {
try {
if (isSingleInstance(clazz)) {
return (UriHandler) SingletonPool.get(clazz, null);
} else {
return (UriHandler) clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
return null;
}
由PageAnnotationHandler在加载由注解处理器生成的 PageAnnotationInit_xxxxxx 时注册的
由UriAnnotationHandler在加载由注解处理器生成的UriAnnotationInit_xxxxxx 时注册的
WMRouterTransform
public void transform(TransformInvocation invocation) {
WMRouterLogger.info(TRANSFORM + "start...");
long ms = System.currentTimeMillis();
//非增量编译,先清空输出目录
if (!invocation.isIncremental()) {
try {
invocation.getOutputProvider().deleteAll();
} catch (IOException e) {
WMRouterLogger.fatal(e);
}
}
Set initClasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
Set deleteClasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
BaseTransform baseTransform = new BaseTransform(invocation, new TransformCallBack() {
@Nullable
@Override
public byte[] process(@NotNull String className, @Nullable byte[] classBytes) {
String checkClassName = ClassUtils.path2Classname(className);
if (checkClassName.startsWith(Const.GEN_PKG_SERVICE)) {
WMRouterLogger.info(TRANSFORM + "className = %s, checkClassName = %s", className, checkClassName);
initClasses.add(className);
}
return null;
}
}, false);
baseTransform.setDeleteCallBack(new DeleteCallBack() {
@Override
public void delete(String className, byte[] bytes) {
String checkClassName = ClassUtils.path2Classname(className);
if (checkClassName.startsWith(Const.GEN_PKG_SERVICE)) {
deleteClasses.add(className);
}
}
});
baseTransform.openSimpleScan();
baseTransform.startTransform();
File dest = invocation.getOutputProvider().getContentLocation(
"WMRouter", TransformManager.CONTENT_CLASS,
ImmutableSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY);
generateServiceInitClass(dest.getAbsolutePath(), initClasses, deleteClasses);
WMRouterLogger.info(TRANSFORM + "cost %s ms", System.currentTimeMillis() - ms);
}
private void generateServiceInitClass(String directory, Set classes, Set deleteClass) {
if (classes.isEmpty()) {
WMRouterLogger.info(GENERATE_INIT + "skipped, no service found");
return;
}
File dest = new File(directory, INIT_SERVICE_PATH + SdkConstants.DOT_CLASS);
if (!dest.exists()) {
try {
WMRouterLogger.info(GENERATE_INIT + "start...");
long ms = System.currentTimeMillis();
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, writer) {
};
// 1、类名
String className = Const.SERVICE_LOADER_INIT.replace('.', '/');
cv.visit(50, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
// 2、init 方法声明 (公开 & 静态)
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
Const.INIT_METHOD, "()V", null, null);
// 3、init 方法体
// 遍历传递的 classes 参数,调用其 init 方法
mv.visitCode();
for (String clazz : classes) {
String input = clazz.replace(".class", "");
input = input.replace(".", "/");
mv.visitMethodInsn(Opcodes.INVOKESTATIC, input,
"init",
"()V",
false);
}
mv.visitMaxs(0, 0);
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
cv.visitEnd();
// 4、将class字节码写到对应位置
dest.getParentFile().mkdirs();
new FileOutputStream(dest).write(writer.toByteArray());
WMRouterLogger.info(GENERATE_INIT + "cost %s ms", System.currentTimeMillis() - ms);
} catch (IOException e) {
WMRouterLogger.fatal(e);
}
} else {
try {
modifyClass(dest, classes, deleteClass);
} catch (IOException e) {
e.printStackTrace();
}
}
}
1、Router.startUri ==> RootUriHandler.startUri (实际是DefaultRootUriHandler,在Router.init时传递
DefaultRootUriHandler创建Request, 调用handle) ==> UriHandle.handle
DefaultRootUriHandler 继承 RootUriHandler 继承 ChainedHandler 继承 UriHandler
handle 方法首先判断是否应该处理 shouldHandle (ChainedHandler中,只要 mHandlers列表 不为空就应该处理,mHandlers 在初始化的时候被赋值)
public DefaultRootUriHandler(Context context, @Nullable String defaultScheme, @Nullable String defaultHost) {
super(context);
mPageAnnotatiOnHandler= createPageAnnotationHandler();
mUriAnnotatiOnHandler= createUriAnnotationHandler(defaultScheme, defaultHost);
// 按优先级排序,数字越大越先执行
// 处理RouterPage注解定义的内部页面跳转,如果注解没定义,直接结束分发
addChildHandler(mPageAnnotationHandler, 300);
// 处理RouterUri注解定义的URI跳转,如果注解没定义,继续分发到后面的Handler
addChildHandler(mUriAnnotationHandler, 200);
// 添加其他用户自定义Handler...
// 都没有处理,则尝试使用默认的StartUriHandler直接启动Uri
addChildHandler(new StartUriHandler(), -100);
}
public void handle(@NonNull final UriRequest request, @NonNull final UriCallback callback) {
if (shouldHandle(request)) {
Debugger.i("%s: handle request %s", this, request);
if (mInterceptor != null && !request.isSkipInterceptors()) {
mInterceptor.intercept(request, new UriCallback() {
@Override
public void onNext() {
// 1、先调用拦截器的方法,拦截器调用完成之后再调用 handleInternal
handleInternal(request, callback);
}
@Override
public void onComplete(int result) {
callback.onComplete(result);
}
});
} else {
// 没有拦截器直接 handleInternal
handleInternal(request, callback);
}
} else {
Debugger.i("%s: ignore request %s", this, request);
callback.onNext();
}
}
因为后面的具体 Handler 基本上都是继承自 UriHandler,因此这一段 handler 的代码相当于时一个模板方法模式,对一个UriRequest的处理基本上都分解成如上的三步:
第一步:调用 shouldHandle 判断是否应该处理;
第二步:判断当前 Handler 是否存在拦截器,如果有拦截器先将 UriRequest 交给拦截器处理;
第三步:将请求交给 handlerInternal 进行处理。
2、到目前为止我们的 Handler 实际的类型还是 DefaultRootUriHandler,其 handlerInternal 在 ChainedHandler 中实现。
@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();
}
}
基本就是按照 UriHandler 的顺序依次调用其 handler 方法, UriHandler 在 DefaultRootUriHandler 构造时初始化,并被存储在一个优先级队列中。按照优先级依次是:PageAnnotationHandler、UriAnnotationHandler、StartUriHandler。
3、PageAnnotationHandler
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
protected void handleInternal(final UriRequest request, final UriCallback callback) {
// 1、查找能处理的 Handler
UriHandler h = getChild(request);
if (h != null) {
// 2、调用查找到的Handler的handle方法
h.handle(request, new UriCallback() {
@Override
public void onNext() {
handleByDefault(request, callback);
}
@Override
public void onComplete(int resultCode) {
callback.onComplete(resultCode);
}
});
} else {
// 3、调用默认 Handler 的 handle 方法
handleByDefault(request, callback);
}
}
// 初始化时注册的路由处理器就是放在 mMap 中
private UriHandler getChild(@NonNull UriRequest request) {
String path = request.getUri().getPath();
UriHandler handler;
if (TextUtils.isEmpty(path)) {
return mMap.get("/");
}
if (!TextUtils.isEmpty(mPathPrefix)) {
path = path.substring(mPathPrefix.length());
}
path = Util.appendSlash(path);
handler = mMap.get(path);
if (handler == null) { //modify by zyh 当常规的路由表匹配不上时,从restfulMap中查找匹配的路由信息
handler = getRestfulChild(request);
}
if (handler == null) {
handler = mMap.get("/");
}
return handler;
}
先调用 mInitHelper.ensureInit() 判断是否已经初始化,没有初始化则执行初始化操作,初始化其实就是上面的扫描注解处理器生成的样板代码,注册最终路由处理器的过程。
之后在调用基类UriHandler的handle方法进行处理,按照上面的思路,最终会调用到 handleInternal 中,PageAnnotationHandler继承自 PathHandler,PathHandler 中实现了该方法。
在 mMap 中查找到能够处理的 UriHandler 调用其 handler 方法,否则调用默认 handler 的 handle 方法(PageAnnotationHandler)没有默认 Handler
4、FragmentTransactionHandler
FragmentTransactionHandler 就是由 PageAnnotationHandler 注册的一种路由处理器类型,用来路由到一个 Fragment页面。同理我们主要看其 handleInternal 方法。
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
if (TextUtils.isEmpty(mClassName)) {
Debugger.fatal("FragmentTransactionHandler.handleInternal()应返回的带有ClassName");
callback.onComplete(UriResult.CODE_BAD_REQUEST);
return;
}
StartFragmentAction action = request.getField(StartFragmentAction.class, StartFragmentAction.START_FRAGMENT_ACTION);
if (action == null) {
Debugger.fatal("FragmentTransactionHandler.handleInternal()应返回的带有StartFragmentAction");
callback.onComplete(UriResult.CODE_BAD_REQUEST);
return;
}
if (!request.hasField(FRAGMENT_CLASS_NAME)) {
//判断一下,便于被替换
request.putField(FRAGMENT_CLASS_NAME, mClassName);
}
// Extra
Bundle extra = request.getField(Bundle.class, FIELD_INTENT_EXTRA);
boolean success = action.startFragment(request, extra);
// 完成
callback.onComplete(success ? UriResult.CODE_SUCCESS : UriResult.CODE_BAD_REQUEST);
}
public boolean startFragment(@NonNull UriRequest request, @NonNull Bundle bundle) throws ActivityNotFoundException, SecurityException {
String fragmentClassName = request.getStringField(FragmentTransactionHandler.FRAGMENT_CLASS_NAME);
try {
Fragment fragment = Fragment.instantiate(request.getContext(), fragmentClassName, bundle);
if (fragment == null) {
return false;
}
FragmentTransaction transaction = mFragmentManager.beginTransaction();
switch (mStartType) {
case TYPE_ADD:
transaction.add(mContainerViewId, fragment, mTag);
break;
case TYPE_REPLACE:
transaction.replace(mContainerViewId, fragment, mTag);
break;
}
if (mAllowingStateLoss) {
transaction.commitAllowingStateLoss();
} else {
transaction.commit();
}
return true;
} catch (Exception e) {
Debugger.e("FragmentTransactionUriRequest",e);
return false;
}
}
5、UriAnnotationHandler
如果前一步的 PageAnnotationHandler 没有处理,下一步就由UriAnnotationHandler来处理。其处理逻辑和 PageAnnotationHandler 相似,也是先初始化,然后再调用 UriHandler 的 handle 方法。和 PageAnnotationHandler 不同的是 UriAnnotationHandler 直接继承 UriHandler,而前者直接继承 PathHandler。
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
PathHandler pathHandler = getChild(request);
if (pathHandler != null) {
pathHandler.handle(request, callback);
} else {
// 没找到的继续分发
callback.onNext();
}
}
private final Map mMap = new HashMap<>();
private PathHandler getChild(@NonNull UriRequest request) {
return mMap.get(request.schemeHost());
}
由上面分析可知最终也是进入 handleInternal 方法中,首先从 mMap 中通过 scheme + host 拿到对应的 PathHandler,再调用其 handle 方法 (也是 UriHandler 的 handle)
最终也是调用到 PathHandler 的 handleInternal 方法
在 UriAnnotationHandler 每个 scheme + host 对应一个 PathHandler,而一个 PathHandler 中又可以注册多个路由。
在 PageAnnotationHandler 只有一个 PathHandler (就是其自身,其scheme和host固定)
后面的处理和 PageAnnotationHandler 中分析的类似了:在 PathHandler 查找到具体的路由处理器,调用对应的 handle 方法
6、ActivityClassNameHandler
该 Handler 就是由 UriAnnotationHandler 解析注册的。继承 AbsActivityHandler,最终交给其 handleInternal方法处理。
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
// 创建Intent
Intent intent = createIntent(request);
if (intent == null || intent.getComponent() == null) {
Debugger.fatal("AbsActivityHandler.createIntent()应返回的带有ClassName的显式跳转Intent");
callback.onComplete(UriResult.CODE_ERROR);
return;
}
intent.setData(request.getUri());
UriSourceTools.setIntentSource(intent, request);
// 启动Activity
request.putFieldIfAbsent(ActivityLauncher.FIELD_LIMIT_PACKAGE, limitPackage());
int resultCode = RouterComponents.startActivity(request, intent);
// 回调方法
onActivityStartComplete(request, resultCode);
// 完成
callback.onComplete(resultCode);
}
4、其他
WMRouter除了页面路由的功能外还提供了ServiceLoader的功能,此外还有@Autowired
注解可以自动注入路由传递的参数。