ARouter调用过程
ARouter在使用过程中,无论是通过path,还是类名(Provider类型的服务节点即可以通过path获取,也可以通过类名获取),都是先构造Postcard作为信息的载体(包括path,group,携带的参数等)为起点,最后通过调用navigation方法进行页面跳转或获取相应的服务、Fragment。
path调用方式
先看看通过path的调用:
protected Postcard build(String path, String group) {
if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
//path预处理,需要自己实现PathReplaceService类,否则这里返回null
if (null != pService) {
path = pService.forString(path);
}
//构建postcard
return new Postcard(path, group);
}
}
Postcard通可以过一系列的链式调用添加参数,最后调用自己的navigation方法,此方法有很多重载方法,但最终是调用Arouter的navigation方法,Arouter只是个代理类,最后走的还是_Arouter类的navigation方法:
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
//完善postcard,很重要的方法,涉及每个group下节点列表的加载等,后面单独介绍
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {//根据postcard中的path信息没有找到路由节点的情况
//... 省略log代码
if (null != callback) {
callback.onLost(postcard);
} else { // No callback for this invoke, then we use the global degrade service.
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
if (null != callback) {
callback.onFound(postcard);
}
//判断是否需要做拦截处理,IProvider、Fragment不需要做拦截处理
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
//doInterceptions方法里会处理拦截逻辑
//interceptorService是一个Provider类型的服务接口实例
//实现类是来自Arouter内部的InterceptorServiceImpl,后面会详细分析
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
//继续执行路由逻辑,所以在拦截器中处理后一定要调这个方法,否则不会继续执行路由
_navigation(context, postcard, requestCode, callback);
}
@Override
public void onInterrupt(Throwable exception) {
//做了拦截,不在继续分发
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
} else {
//跳过拦截器,直接执行路由逻辑
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
先继续看_navigation方法:
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) { //根据路由节点类型的不同做不同的逻辑处理
case ACTIVITY: //Activity页面跳转
// Build intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// Navigation in main looper.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//进行页面跳转
if (requestCode > 0) { // Need start for result
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
//转场动画
if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
});
break;
case PROVIDER: //provider类型的节点则返回该provider服务
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
//Fragment类型的就返回该Fragment的实例对象
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
if (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;
}
逻辑不复杂,如果是Activity类型的,就跳转到相应的Activity页面,如果是Provider类型,就返回对应的服务实例,如果是Fragment类型,就返回对应的Fragment实例。
回过头先看看LogisticsCenter的completion方法:
public synchronized static void completion(Postcard postcard) {
//...
//根据path从Warehouse类的routes中获取缓存的节点
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
//第一次获取为null
if (null == routeMeta) { // Maybe its does't exist, or didn't load.
//Warehouse.groupsIndex在初始化的时候以group值为key,缓存了编译期自动生成的某个group路由节点列表类
//根据group值,获取group类
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta.
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// Load route and cache it into memory, then delete from metas.
try {
//创建该group类的实例
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
//以Warehouse.routes为参数调用其loadInto方法
//loadInto方法会将该group下的所有节点都缓存到Warehouse.routes中
//以path为key,value以RouteMeta为载体
iGroupInstance.loadInto(Warehouse.routes);
//加载完,将该group从缓存中移除
Warehouse.groupsIndex.remove(postcard.getGroup());
} catch (Exception e) {
//...
}
//重新调用completion方法,这时候获取的RouteMeta不为null,走else的逻辑
completion(postcard); // Reload
}
} else {
//根据RouteMeta信息完善postcard信息
postcard.setDestination(routeMeta.getDestination());//设置节点对应的类名
postcard.setType(routeMeta.getType());//设置节点的类型
postcard.setPriority(routeMeta.getPriority());//设置节点的优先级
postcard.setExtra(routeMeta.getExtra());//设置携带的参数
Uri rawUri = postcard.getUri();
//只有通过uri跳转时才不为null
if (null != rawUri) { // Try to set params into bundle.
//从uri中获取参数,然后保存到postcard中
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
// Set value by its type, just for params which annotation by @Param
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}
// Save params name which need auto inject.
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
// Save raw uri
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
//对Fragment和provider类型的节点做特殊处理
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must be implememt IProvider
//如果是provider类型的节点,则获取其实例
//获取具体实现类名
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
//尝试从缓存中获取实例,第一次返回null
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
IProvider provider;
try {
//创建provider的实例对象
provider = providerMeta.getConstructor().newInstance();
//调用其初始化方法
provider.init(mContext);
//将改provider实例缓存到Warehouse.providers中
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
//无论是缓存的还是新建的,都将实例对象保存到postcard中
postcard.setProvider(instance);
//设置provider类型的路由不能被拦截器拦截
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
//设置Fragment类型的路由不能被拦截器拦截
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
通过completion方法,完善了作为路由载体的postcard,这过程中还包含了对路由节点的加载缓存,provider类型的服务创建和缓存。
接着看看Arouter的拦截器的工作,Arouter内部提供了接口和实现类,看下接口定义和实现类:
接口InterceptorService如下:
public interface InterceptorService extends IProvider { //继承自IProvider,是个provider类型节点服务
/**
* Do interceptions
*/
void doInterceptions(Postcard postcard, InterceptorCallback callback);
}
Arouter提供的实现类InterceptorServiceImpl,而这个服务是在Arouter初始化的最后创建的,定位到_Arouter类中的相关代码如下:
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
可以看出,内部的provider服务也是通过Arouter这种统一路由的方式获取的,上述代码中的path对应的是InterceptorServiceImpl这个实现类,从之前的分析得知,通过navigation方法,Arouter会创建InterceptorServiceImpl的实例,然后调用其init方法,最后返回给服务,先看下InterceptorServiceImpl的定义和init方法:
@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {
private static boolean interceptorHasInit;
private static final Object interceptorInitLock = new Object();
//...省略其他代码
@Override
public void init(final Context context) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
//编译初始化阶段缓存在Warehouse.interceptorsIndex中的各个IInterceptor实现类,即用户自己添加的拦截器
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
//创建拦截器的实例
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
//调用其init方法,可以根据需求在里面做些初始化操作
iInterceptor.init(context);
//将拦截器的实例缓存起来
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
//...
}
}
interceptorHasInit = true;
synchronized (interceptorInitLock) {
interceptorInitLock.notifyAll();
}
}
}
});
}
所以,在Arouter初始化结束后,就会主动去获取InterceptorServiceImpl服务,并将实例赋值给_Arouter的全局变量interceptorService,方便以后使用。而在获取InterceptorServiceImpl服务期间会调用其init方法,在init方法中,会加载所有用户定义的拦截器,然后缓存在Warehouse.interceptors中。当进行页面跳转时,Arouter会调用interceptorService的doInterceptions方法,看下该方法的实现:
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
//...省略不分代码
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
//CancelableCountDownLatch相对于CountDownLatch只是增加了cancel方法,可以提早结束CountDownLatch的阻塞状态
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
//每个拦截器的执行过程,后面分析
_excute(0, interceptorCounter, postcard);
//可以设置超时时间
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
//理论上到这里interceptorCounter.getCount()的大小应该等于0,异常情况如:超时
//所有拦截器都已处理,或者某个拦截器进行了拦截操作(会调用CancelableCountDownLatch的cancel方法,将CancelableCountDownLatch的count递减到0)
if (interceptorCounter.getCount() > 0) {
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) {
// Maybe some exception in the tag.
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
每个拦截器的遍历执行放在_excute方法中:
private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
//从0开始遍历拦截器,拦截器是按优先级降序排序的,也就是从高优先级的开始遍历
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
//调用拦截器的process方法
iInterceptor.process(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
// Last interceptor excute over with no exception.
counter.countDown();
//递归调用
_excute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know.
}
@Override
public void onInterrupt(Throwable exception) {
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
counter.cancel();
}
});
}
}
以上就是拦截器的相关处理逻辑。
类名调用方式
这个只支持provider类型,定位下_Arouter的代码:
protected <T> T navigation(Class<? extends T> service) {
try {
Postcard postcard = LogisticsCenter.buildProvider(service.getName());
// Compatible 1.0.5 compiler sdk.
if (null == postcard) { // No service, or this service in old version.
postcard = LogisticsCenter.buildProvider(service.getSimpleName());
}
LogisticsCenter.completion(postcard);
return (T) postcard.getProvider();
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
return null;
}
}
除了构建postcard的逻辑有点不一样,其他的基本和path调用的一样,看下LogisticsCenter的buildProvider方法:
public static Postcard buildProvider(String serviceName) {
//根据provider的类名,从缓存中获取节点信息,然后构造postcard
//Warehouse.providersIndex中的缓存信息是Arouter初始化的时候加载进去的,key就是provider的类名
RouteMeta meta = Warehouse.providersIndex.get(serviceName);
if (null == meta) {
return null;
} else {
//后面的逻辑就和path调用的一样了
return new Postcard(meta.getPath(), meta.getGroup());
}
}
自动赋值逻辑
之前分析调用过程并没有涉及到自动赋值逻辑,因为自动赋值需要用户在需要自动赋值的activity或fragment中主动调用Arouter的inject方法,比如在Activity的onCreate方法中调用:
@Autowired
String name;
@Autowired(required = true)
TestObj obj;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
//用户需要单独调用此方法
ARouter.getInstance().inject(this);
//...
}
看下这个方法做了些什么:
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
autowiredService.autowire(thiz);
}
}
代码很简单,做了两件事:
1.获取AutowiredService服务
2.调用AutowiredService的autowire方法(自动赋值)
“/arouter/service/autowired”这个path对应的是Arouter提供的AutowiredServiceImpl类,同样是通过Arouter获取的服务,我们知道过程中会调用AutowiredServiceImpl的init方法,看下AutowiredServiceImpl的定义:
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
private LruCache<String, ISyringe> classCache;
private List<String> blackList;
@Override
public void init(Context context) {
classCache = new LruCache<>(66);
blackList = new ArrayList<>();
}
@Override
public void autowire(Object instance) {
//获取要自动赋值的类的类名,而在编译期通过AutowireProcessor自动生成的类命名都是按照当前类名+固定后缀的形式
String className = instance.getClass().getName();
try {
if (!blackList.contains(className)) {
//先从缓存中获取ISyringe实例
ISyringe autowiredHelper = classCache.get(className);
if (null == autowiredHelper) { // No cache.
//第一次没有缓存,利用类名,通过反射构造实例
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
//以需要被自动赋值的类为参数,调用实例的inject方法
//inject的方法体是在编译期自动生成的,主要是根据不同类型对变量进行赋值
autowiredHelper.inject(instance);
//将实例缓存起来
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
//加入黑名单
blackList.add(className); // This instance need not autowired.
}
}
}
在init方法中创建了缓存的集合,以及黑名单列表,AutowiredServiceImpl会把自动赋值过程中抛异常的类加入到黑名单列表中,下次直接跳过。通过调用AutowiredServiceImpl的autowire方法,就能达到自动赋值的目的。
所以用户需要对变量自动赋值,一定要在类中主动调用Arouter的inject方法。
网友评论