前面的文章我们大致了解了
WMRouter的实现原理,本文就找一个具体的实例来看一下对于一个Activity页面的导航是如何实现的。
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打开之前调用。监听登录状态,登录成功后则跳转目标界面。源码原理前面其实已经看过了,这里就不仔细看了。
作者:susion哒哒
链接:https://www.jianshu.com/p/221908cd237d