模块化能力支持项:
用于跨模块通信使用,核心设计思想是参考了SOA(面向服务架构) 的设计方式。
具体到 Android 侧就是 AIDL 类似的实现:
例如当前有两个模块:A订单模块、B登录模块,下单需要获取用户信息。
这个业务场景就是,A需要使用获取用户信息的服务,B需要向外提供一个获取用户信息的服务。
首先声明一个接口,放入公共依赖层
// 假设当前有一个用户信息获取服务
public interface IUserService {
String getUserInfo();
}
也就是上面例子的 A订单模块,他需要使用获取用户信息的服务
A无需关心,IUserService
这个接口服务是谁提供的,他只需要知道自己需要使用这样的一个服务就行了。
注:如果没有提供服务的提供方,TheRouter.get()
可能返回null
TheRouter.get(IUserService::class.java)?.getUserInfo()
服务提供方需要声明一个提供服务的方法,用@ServiceProvider
注解标记。
/**
* 方法名不限定,任意名字都行
* 返回值必须是服务接口名,如果是实现了服务的子类,需要加上returnType限定(例如下面代码)
* 方法必须加上 public static 修饰,否则编译期就会报错
*/
@ServiceProvider
public static IUserService test() {
return new IUserService() {
@Override
public String getUserInfo() {
return "返回用户信息";
}
};
}
// 也可以直接返回对象,然后标注这个方法的服名是什么
@ServiceProvider(returnType = IUserService.class)
public static UserServiceImpl test() {
xxx
}
注:每个服务只能有一个服务提供方,类似ARouter
那种多个接口实现类,我们认为是不符合面向服务设计规范的。如果你一定要有多个服务,并且由使用方决定在什么时间使用哪个服务,建议选择如下改造方案:
ActionManager
替换实现。使用场景:单模块调试时,可能会有需要 mock 其他模块提供的服务,TheRouter 允许自定义其他模块的实现。
Interceptor interceptor = new Interceptor() {
@Override
public <T> T interception(Class<T> clazz, Object... params) {
if (clazz == IUserService.class) {
return new IUserService();
}
return null;
}
};
TheRouter.getRouterInject().addInterceptor(interceptor);
服务提供方运行对提供的服务做配置,对于无状态的服务,尽可能使用缓存方式减少对象创建次数,而有状态的服务,则每次创建新对象保证多次调用有不会互相污染状态(例如订单状态管理、商品销售状态等服务)。
声明服务缓存只需要在接口协议上新增额外注解即可,例如下面示例代码:
注:如果两个注解同时被添加,则只有Singleton
会生效。
注:@Singleton
和@NewInstance
需要加在接口协议上。
// 注:如果都不加,默认是LRU+软引用缓存
// 如果两个注解同时被添加,则只有Singleton会生效。
@Singleton // 对外部调用方而言相当于这个对象声明成了单例
@NewInstance // 每次都会返回新对象
public interface IUserService {
public String getUserInfo();
}
@ServiceProvider
public static IUserService test() {
return new IUserService() {
@Override
public String getUserInfo() {
return "返回用户信息";
}
};
}
从1.1.2-rc7
版本开始,ServiceProvider
支持给类设置注解。
// 服务提供方
@ServiceProvider
public class TestClassAnnotation implements ITestClassAnnotation {
}
//服务使用方
TheRouter.get(ITestClassAnnotation.class)
如果一个接口都没有实现,默认的返回类型为当前类本身。
如果 类有多个接口需要实现,则必须显示声明returnType
,例如:
// 服务提供方
@ServiceProvider(returnType = ITestClassAnnotation.class)
public class TestClassAnnotation implements ITestClassAnnotation, ITest0 {
}
//服务使用方
TheRouter.get(ITestClassAnnotation.class)
// 服务提供方
@ServiceProvider
public static IUserService test(String str) {
return new IUserService() {
@Override
public String getUserInfo() {
return str;
}
};
}
//服务使用方
TheRouter.get(IUserService.class, "user Info");
// 服务提供方
@ServiceProvider(returnType = ITestClassAnnotation.class, params={String.class})
public class TestClassAnnotation implements ITestClassAnnotation, ITest0 {
public TestClassAnnotation(String str){}
}
//服务使用方
TheRouter.get(ITestClassAnnotation.class, "hello")
如果你的类有父类实现了接口协议,而你又不想显示声明returnType
,例如下面这种场景。我们也提供了一个编译选项可供使用,在gradle.properties
文件中加入 USE_EXTENSION=true
注 :请 谨慎 开启 USE_EXTENSION
。当开启后,所有协议判断会使用isAssignableFrom
去判断,而不再是equals
,对运行时性能会有较大影响。
public class SuperTestClassAnnotation implements ITestClassAnnotation, ITest0 {
}
// 服务提供方
@ServiceProvider
public class TestClassAnnotation extends SuperTestClassAnnotation{
}
// 当在`gradle.properties`文件中加入 `USE_EXTENSION=true`后,
// 表示允许接口协议拥有继承关系,所以可以使用如下两个协议获取并使用服务
TheRouter.get(ITestClassAnnotation.class)
// 或
TheRouter.get(ITest0.class)