文章来源自作者的Android进阶计划(https://github.com/SusionSuc/AdvancedAndroid)
其实在第一篇文章的时候已经介绍过ARouter
中的InterceptorService
、GlobalDegradeService
也是框架在运行时期动态加载的。即使这两个类位于其它的模块。
所以ARouter
也是具有WMRouter
的ServiceLoader
相似的功能的。本文就来看一下这个功能。
拦截器Service的加载
先来看一下ARouter
的拦截器的实现类:
@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {}
即也使用了@Route
注解标记,按照我们前面文章的分析,这个类也会在运行的时候被动态的加载到路由表Warehouse.routes
和Warehouse.groupIndex
中。
我们看一下ARouter
是如何在代码中获取这个类的实现类的:
static void afterInit() { //这个代码在ARouter初始化完毕后调用
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
这里可能就有疑问了,为什么ARouter.getInstance().build("/arouter/service/interceptor").navigation()
可以得到一个对象?
我们已经知道@Route
标记的类在RouteProcessor
处理时会生成对应的RouteMeta
。其实RouterMeta是有类型的,我们来看一下注解扫描生成RouteMeta
那一段代码:
TypeMirror tm = element.asType(); //tm 即注解标注的那个类
if (types.isSubtype(tm, type_Activity)) {// Activity
routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
routeMeta.setInjectConfig(injectConfig);
} else if (types.isSubtype(tm, iProvider)) {// IProvider
routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
} else if (types.isSubtype(tm, type_Service)) { // Service
routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
}
即如果被注解标注的类是个Activity
,那么RouteMeta
的类型就是RouteType.ACTIVITY
。如果是IProvider
,那么对应的类型就是RouteType.PROVIDER
。
其实InterceptorServiceImpl
就是IProvider
类型:
public interface InterceptorService extends IProvider {
interceptions(Postcard postcard, InterceptorCallback callback);
}
我们前面只看了ARouter
只在路由过程中对RouteType.ACTIVITY
的处理,这里我们看一下对RouteType.PROVIDER
的处理:
//_ARouter.java
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
switch (postcard.getType()) {
case ACTIVITY:
//对activity进行跳转
break;
case PROVIDER:
return postcard.getProvider();
....
default:
return null;
}
return null;
}
即对于RouteType.PROVIDER
直接返回了postcard.getProvider()
。 好我们来看一下postcard.getProvider()
是什么? 我们来看一下LogisticsCenter
根据RouteMeta
组装Postcard
的那一段代码:
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must implement IProvider
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
//..如果 instance 为空的话则实例化 `providerMeta`对应的类,然后放入到`Warehouse.providers`
postcard.setProvider(instance);
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
其实这里就可以猜测,对于
@Route
标记的IProvider
接口,也会创建一个Warehouse.providers
,用来保存这些实例。
所以postcard.getProvider()
就是一个 InterceptorServiceImpl
对象。综上:
static void afterInit() { //这个代码在ARouter初始化完毕后调用
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
interceptorService
就是InterceptorServiceImpl
对象。
好到这里我们知道了InterceptorService
是如何加载的了。Interceptor
是怎加载的呢?
这里就不去仔细追究源码了,直接解释一下大致原理。
- 在ARoute中,拦截器可以使用
@Interceptor
来标注 -
InterceptorProcessor
会动态生成一个注册文件,类似于Activity的路由节点注册的java类。 - 在ARouter初始化的时候,会注册到
Warehouse.interceptors
-
InterceptorService
在初始化的时候,会实例化Warehouse.interceptors
表中记录的类
我们只看一下InterceptorServiceImpl
的初始化方法,来证明上面所说的 :
@Override public void init(final Context context) {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) { //这段代码是在异步线程执行的
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
iInterceptor.init(context);
Warehouse.interceptors.add(iInterceptor);
}
......
}
}
IProvider 的妙用
看了上面这个功能,我们是不是可以利用它来加载一个其他库的实现类,比如一个UI的实现类? 答案是可以的,比如我们在一个库中定义了这个类:
@Route(path = "/custom/ui1")
public class MyCustomUi implements IProvider { //必须实现 IProvider 接口
public MyCustomUi() { }//要提供默认构造方法
@Override
public void init(Context context) {}
}
我们在主工程中,这样就可以获得它的实例:
IProvider ui1 = (IProvider) ARouter.getInstance().build("/custom/ui1").navigation();
这个功能是不是和WMRouter
的ServiceLoader
有异曲同工之妙?
@Autowired 参数的自动注入
ARouter
是支持在Activity的属性上标记@Autowired
注解,然后在跳转的时候自动将参数赋值到这些属性上。比如:
ARouter.getInstance()
.build("/test/activity1")
.withInt("age", 23)
.navigation();
@Route(path = "/test/activity1")
public class Test1Activity extends AppCompatActivity {
@Autowired
int age = 10;
@Override
protected void onCreate(Bundle savedInstanceState) {
ARouter.getInstance().inject(this); // 在 onCreate中必须调用这个方法
}
}
其实这个功能的实现也是基于上面@Route
机制的,因此这里就大致讲一下原来和关键代码:
-
AutowiredProcessor
会在编译时扫描@Autowired
注解,并生成下面的文件
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
@Override
public void inject(Object target) {
Test1Activity substitute = (Test1Activity)target;
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
}
}
-
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);
}
}
- 来看一下
AutowiredService
的实现类
@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) { //instance 就是 Test1Activity的实例
....
//autowiredHelper其实就是Test1Activity$$ARouter$$Autowired
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
autowiredHelper.inject(instance); // 调用 Test1Activity$$ARouter$$Autowired.inject()
...
}
}
网友评论