模块名是配置在build.gradle中的参数,一般情况下是module名称,如app或其他自定义的module名称:
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]
}
}
}
}
ARouter?Root?模块名.class
这个类实现了IRouteRoot接口,记录了所有的分组信息,通过group名称,可以找到对应group下 所有的路由信息。如demo中的例子:
public class ARouter?Root?app implements IRouteRoot {
public ARouter?Root?app() {
}
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("test", test.class);
routes.put("yourservicegroupname", yourservicegroupname.class);
}
}
通过区分group可以实现路由表的懒加载,只有用到某个group时才将它下面的所有路由信息加载到内存中,减少初始化的时间和内存占用。具体实现过程在LogisticsCenter.completion()中:
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) { // Maybe its does't exist, or didn't load.
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 {
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
completion(postcard); // Reload
}
} else {
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
if (null != rawUri) { // Try to set params into bundle.
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());
}
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);
if (null == instance) { // There's no instance of this provider
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
postcard.setProvider(instance);
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
流程如下:
- 查询某个path的路由信息是否存在
- 查询该group的组信息
- 将该group下的所有路由信息全部加载到内存中
- 重新加载该path,根据类型和路由存储的类信息,加载对应的对象实例(对PROVIDER和FRAGMENT做特殊处理,标记不需要调用拦截器,以及调用IProvider的init(context)方法)
ARouter?Providers?模块名.class
这个类实现了IProviderGroup接口,主要记录了服务提供者的接口的全限定类名和具体的类信息,服务提供者都是实现了IProvider的类。
作用是能根据具体的服务接口来实例化服务,只对接口只有一个实现类时有效,如果有两个类实现了某个服务接口,不能保证通过类型获得的服务的具体类型:
有两个类HelloServiceImpl和HelloService2实现HelloService接口,APT生成的注册类如下:
public class ARouter?Providers?app implements IProviderGroup {
public ARouter?Providers?app() {
}
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", (Map)null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloService2.class, "/yourservicegroupname/hello2", "yourservicegroupname", (Map)null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/yourservicegroupname/json", "yourservicegroupname", (Map)null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/yourservicegroupname/single", "yourservicegroupname", (Map)null, -1, -2147483648));
}
}
可以看到调用了两次map的put方法,key是接口的全限定名,value是两个具体的实现类,运行时只有后面的put有效,所以实际的效果跟APT处理时的顺序有关。所以在这种情况下应该根据路由的名称来获取具体的服务类。
ARouter?Interceptors?模块名.class
这个类实现了IInterceptorGroup接口,保存了拦截器和优先级。
public class ARouter?Interceptors?app implements IInterceptorGroup {
public ARouter?Interceptors?app() {
}
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(7, Test1Interceptor.class);
}
}
拦截器的使用在InterceptorServiceImpl._execute()中,调用在 _ARouter.navigation()中。考虑到拦截可能是异步的,所以InterceptorServiceImpl.doInterceptions()执行拦截时使用了CancelableCountDownLatch确保所有的拦截器都被处理之后,再进行后续操作。
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
checkInterceptorsInitStatus();
if (!interceptorHasInit) {
callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
return;
}
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
_execute(0, interceptorCounter, postcard);
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
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);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
ARouter?Group?Group名称.class
这个类实现了IRouteGroup接口,记录了同一个group下所有的路由信息,包括activity,fragment,IProvider。支持的类型定义在RouteType的枚举中:
public enum RouteType {
ACTIVITY(0, "android.app.Activity"),
SERVICE(1, "android.app.Service"),
PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
BOARDCAST(-1, ""),
METHOD(-1, ""),
FRAGMENT(-1, "android.app.Fragment"),
UNKNOWN(-1, "Unknown route type");
}
路由信息实现了通过一个字符串找到对应的类,做到了代码层面的解耦。
路由信息的使用在_ARouter.__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:
// 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);
}
// 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();
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?ARouter?Autowired.class
这个类实现了ISyringe接口,主要的作用是为使用了@Autowired注解的activity的属性进行注入。流程:
- APT搜集activity中的@Aurowired注解,生成一个activity?ARouter?Autowired.class的类
- activity在onCreate()方法中调用
ARouter.getInstance().inject(this); - ARouter通过路由("/arouter/service/autowired")实例化AutowiredServiceImpl.java
- AutowiredServiceImpl.autowire()根据传入的activity的名称找到对应的activity?ARouter?Autowired.class并实例化,强转成ISyringe接口,并调用inject()方法
- 在inject()中,调用activity.getIntent().getxxx,获取到各个属性
如TestAct中有两个属性加了注解(Autowired跟Route路由注解无关):
public class TestAct extends Activity {
@Autowired
int age;
@Autowired
String name;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this);
}
}
生成的类如下,从intent中获取参数:
public class TestAct?ARouter?Autowired implements ISyringe {
private SerializationService serializationService;
public TestAct?ARouter?Autowired() {
}
public void inject(Object target) {
this.serializationService = (SerializationService)ARouter.getInstance().navigation(SerializationService.class);
TestAct substitute = (TestAct)target;
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.name = substitute.getIntent().getExtras() == null ? substitute.name : substitute.getIntent().getExtras().getString("name", substitute.name);
}
}