ARouter存在的目的就是为了解耦,当两个module之间不存在依赖关系或者只存在单向依赖时,没有办法获取具体的Activity进行跳转,这时就可以借助ARouter来实现。
1. ARouter初始化
ARouter初始化时,会调用LogisticsCenter.init(mContext, executor)
方法,该方法通过反射扫描包下指定的路径,获取编译时根据注解生成的类,然后通过反射将数据缓存到Warehouse
类对应的集合中。
为了解决ARouter初始化时,反射扫描包下的路径导致的耗时操作,ARouter提供了字节码插桩的方式。通过提供的插件在loadRouterMap
方法中处理数据,并将registerByPlugin置为true。
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
loadRouterMap();
if (registerByPlugin) {
//字节码插桩处理
} else {
//反射处理
}
}
2. ARouter跳转
ARouter.getInstance().build("/ar/ma2")
.withInt("age",100)
.withString("name","xiaoli")
.navigation()
这是一个最标准的ARouter的跳转方式,当执行到build方法时,会根据路由的路径拆分出对应的group,创建一个Postcard
对象。Postcard中封装了对应基本数据类型和实现序列化的类的with方法,通过这些方法,可以方便的添加需要传递的参数,封装在Bundle中。当执行到navigation方法时,会按照下面的方法执行。
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
LogisticsCenter.completion(postcard);
if (!postcard.isGreenChannel()) {
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;
}
- LogisticsCenter的completion方法中会找到Postcard中路径对应的RouteMeta对象,该对象是在编译期根据我们添加的路由来动态生成的一个类,包含了路径和注解类相关的信息。通过对应的RouteMeta对象来补全Postcard中需要的目标类的相关信息。
- isGreenChannel= true表示跳过所有的拦截器,默认为false,PROVIDER和FRAGMENT类型会被默认设置greenChannel=true。这里的拦截服务interceptorService在ARouter中指的是
InterceptorServiceImpl
,执行对应的doInterceptions方法开启一个线程池来执行我们创建的拦截器。执行成功的话会回调到onContinue方法中,最终执行_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:
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
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);
}
// Set Actions
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
// Navigation in main looper.
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
case PROVIDER:
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
Class fragmentMeta = postcard.getDestination();
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) {
}
return null;
}
可以看到根据postcard中对应的目标Type,有不同的处理方式。例如ACTIVITY代表调转,FRAGMENT则会创建一个对应的对象并返回。
3. ARouter拦截器
public interface IProvider {
void init(Context context);
}
public interface IInterceptor extends IProvider {
void process(Postcard postcard, InterceptorCallback callback);
}
ARouter中自定义的拦截器需要继承IInterceptor,并重写init
和process
方法。init方法在ARouter初始化时会被调用一次。具体的流程图为:
ARouter.init() -> _ARouter.afterInit()->InterceptorServiceImpl.init()->IInterceptor.init()
ARouter中拦截器的操作从doInterceptions开始,通过默认的线程池开启一个线程来执行拦截器的拦截操作。每一层的拦截器执行完后,需要调用onContinue
交还ARouter控制权,执行下一层拦截器,或者调用onInterrupt
中断路由。
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
_execute(0, interceptorCounter, postcard);
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
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);
}
}
}
private static void _execute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
iInterceptor.process(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
counter.countDown();
_execute(index + 1, counter, postcard);
}
@Override
public void onInterrupt(Throwable exception) {
}
});
}
}
拦截器执行完后会会调到InterceptorServiceImpl
的doInterceptions方法中继续执行下一步,也就是我们上面讲到的ARouter的跳转的最后一步。
4. 服务管理
ARouter中通过实现IProvider
接口可以创建一个服务,然后实现该接口。通过路由注解声明的服务会在编译期被添加到ARouter$$Providers$$app
类中。
interface MiProvider : IProvider {
fun getName():String
}
@Route(path = "/mi/pro",name = "这是测试")
class IMiProviderImpl : MiProvider {
override fun getName() = "yu"
override fun init(context: Context?) {}
}
public class ARouter$$Providers$$app implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.mdy.retrofitdemo.arouter.MiProvider", RouteMeta.build(RouteType.PROVIDER, IMiProviderImpl.class, "/mi/pro", "mi", null, -1, -2147483648));
}
}
通过调用接口的方法,ARouter会帮助我们调用具体的实现类中对应的方法,具体的调用方式分为两种。
依赖查找
通过依赖查找的方式主动去发现服务,主要有以下两种方式,一种是根据服务的Name来获取对应的服务,另一种是根据路由来获取对应的服务。
val miService = ARouter.getInstance().navigation(MiProvider::class.java)
val miService1 = ARouter.getInstance().build("/mi/pro").navigation()
1.根据Name查找
首先来看第一种根据Name来获取服务,执行到ARouter的navigation方法时,具体会执行到_ARouter的navigation方法:
protected <T> T navigation(Class<? extends T> service) {
Postcard postcard = LogisticsCenter.buildProvider(service.getName());
LogisticsCenter.completion(postcard);
return (T) postcard.getProvider();
}
LogisticsCenter的buildProvider方法会根据服务的Name,从Warehouse的providersIndex
Map集合中查找具体的RouteMeta
对象,根据RouteMeta对象中存储的路由信息创建一个Postcard对象。后续调用LogisticsCenter的completion
方法时,会根据Postcard中存储的路由路径,从Warehouse的routes
集合中,获取对应的RouteMeta
对象,根据RouteMeta中存储的type,也就是PROVIDER来获取对应的服务实现类,并添加到postcard的provider
中,最终返回服务实现类。
2.根据路由查找
根据路由查找的流程和前面ARouter的跳转流程基本一致,不同点在于生成的Postcard对象中服务的type类型为PROVIDER
。当执行到最后的_navigation
方法时,返回的是对应的服务实现类。
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
case PROVIDER:
return postcard.getProvider();
}
依赖注入
ARouter中推荐我们使用依赖注入的方法来实现服务的管理。具体的实现为:
public class MiTest2 {
@Autowired(name = "/mi/pro")
MiProvider miProvider;
public MiTest2() {
ARouter.getInstance().inject(this);
}
public String getName() {
return miProvider.getName();
}
}
检测到Autowired注解声明的服务类时,在编译期会自动生成对应的注解类:
public class MiTest2$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
MiTest2 substitute = (MiTest2)target;
substitute.miProvider = (MiProvider)ARouter.getInstance().build("/mi/pro").navigation();
}
}
MiTest2类中通过Autowired
注解声明的服务MiProvider,在执行到MiTest2的构造函数后,会被直接赋值。详细的原理从inject
,该方法会调用到_ARouter的inject方法:
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
autowiredService.autowire(thiz);
}
}
这里AutowiredService
的实现类为AutowiredServiceImpl
,执行到autowire方法时,内部会调用到doInject方法:
private void doInject(Object instance, Class<?> parent) {
Class<?> clazz = null == parent ? instance.getClass() : parent;
ISyringe syringe = getSyringe(clazz);
if (null != syringe) {
syringe.inject(instance);
}
}
getSyringe方法会通过反射获取上面生成的注解类的对象,然后调用对应的inject方法,内部依然是调用
ARouter.getInstance().build("/mi/pro").navigation()
方法获取服务实现类,并赋值给对应的注入类中的服务对象。
通过上面的介绍,可以发现依赖注入方式帮助我们自动查找对应的服务实现类,实现会更加优雅。通过介绍也可以发现拦截器和服务的实现非常类似,都会直接或者间接继承自IProvider接口,且都存在init方法。不同之处在于拦截器在每一次的路由发起时,都会调用,拦截器会在ARouter第一次初始化时,通过线程池异步初始化,在调用拦截器时,如果初始化未完成,路由会等待。而服务只有在第一次调用时才会初始化。
总结
ARouter是帮助App进行组件化构造的框架,目标是帮助App实现多模块之间的跳转,通信和解耦。
注意: module中如果存在编译期生成的注解类的话,打包成aar时会自动打包到aar中。具体的路径为
com.alibaba.android.arouter.routes