项目运行到一定程度,功能和人员都会越来越多,另外对于我们公司项目,还出现了多个App有部分业务流程一样的情况。针对这种问题,除了使用私有库的方式抽取公共模块外,还可以通过组件化(也有地方称为模块化)的方式来进行解耦。
针对我们项目的实际情况,有以下目标要求:
- 各个模块可以单独开发,不需要等待其他功能开发完成。
- 公共的业务流程代码迁移方便。
- 能够控制流程,比如一个页面需要登录才能进入。
- 页面可以很方便跳转,比如可以通过支持字符串跳转。
- 因为我们项目有部分页面使用了Kotlin,所以需要支持Kotlin。
经过调研,发现ARouter能很好的解决我们上面的痛点。ARouter网上的资料已经很完善了,下面主要讲讲,针对我们项目,我们是如何使用它的。
页面跳转
- 定义路由格式:为了避免页面路由冲突,定义路由格式:当前Module名字+当前文件名
通过配置gradle,让当前Module名字自动生成
buildConfigField("String",
"MODULE_SHORT_NAME",
"\""+(project.getName().substring(project.getName().lastIndexOf(".") + 1))+"\"")
- 配置页面路由:
@Route(path = "/" + BuildConfig.MODULE_SHORT_NAME + "/XXXActivity")
public class XXXActivity extends BaseActivity {
/***/
}
- 定义公共路由配置文件
public interface RouterConstant {
/*其他Module*/
// MODULE_NAME 改成自己Module名字
interface MODULE_NAME {
// MODULE_SHORT_NAME改成自己Module名字
String BASE = "/MODULE_SHORT_NAME/";
// XXXActivity改成自己Activity名字
String XXX = BASE + "XXXActivity";
}
}
- 页面跳转
根据第3步定义的配置文件获取配置,最终跳转页面XXXActivity2。
ARouter.getInstance()
.build(RouterConstant.MODULE_NAME.XXX)
.navigation(XXXActivity2.this);
页面跳转拦截器
IInterceptor一旦定义,页面跳转的时候都会进入拦截器,所以需要在拦截器中判断是否真的要进入拦截器。
@Interceptor(priority = 1, name = "登录拦截器")
public class LoginIInterceptor implements IInterceptor {
public static final String IS_CHECK_LOGIN = "IS_CHECK_LOGIN";
private Postcard postcard;
private InterceptorCallback callback;
private Context context;
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
if (callback != null) {
if (postcard != null && postcard.getExtras() != null) {
// 判断是否需要检查登录
boolean isCheckLogin = postcard.getExtras().getBoolean(IS_CHECK_LOGIN);
try {
// 如果需要检查登录 而且 当前没有登录
if (isCheckLogin && !LoginInfoManager.isLogin(context)) {
// 暂存跳转数据和回调流程
this.postcard = postcard;
this.callback = callback;
// 跳转登录页面
ARouterWrapper.build(RouterConstant.LOGIN.LOGIN)
.withFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP)
.navigation(context, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
}
});
return;
}
} catch (Exception e) {
e.printStackTrace();
callback.onContinue(postcard);
}
}
}
// 处理完成,交还控制权
callback.onContinue(postcard);
}
@Override
public void init(Context context) {
this.context = context;
// 添加登录成功消息监听
EventBus.getDefault().register(this);
}
@Subscribe
public void onEventBusReceive(EventBusHandler eventBusHandler) {
/*判断消息类型*/
/*处理逻辑*/
/*释放对象*/
}
}
在要检查登录的页面跳转的时候,添加参数”IS_CHECK_LOGIN“。在拦截器里面判断是否需要验证登录,如果需要验证登录而且当前没有登录,跳转登录页面。登录成功后通过EventBus发送消息,在拦截器里面进行监听,处理相关业务逻辑,继续之前的操作。其他拦截器的逻辑也是类似处理流程,这里就不展开了。
提供程序接口IProvider
当项目中出现下面情况的时候,IProvider就派上用场了。
- A Module需要调用或者使用 B Module里面的方法
- 在项目公共配置里面定义IProvider
public interface XXXProvider extends IProvider {
View createSomeView(Context context);
void doSometing();
}
- 在具体的Module里面实现XXXProvider
@Route(path = "/" + BuildConfig.MODULE_SHORT_NAME + "/XXXProviderImpl")
public class XXXProviderImpl implements XXXProvider {
@Override
public View createSomeView(Context context) {
/*创建View返回*/
}
@Override
public void doSometing() {
/*处理逻辑*/
}
}
- 调用XXXProvider里面方法
// 通过注解获取对象provider,调用XXXProvider里面方法
@Autowired
XXXProvider provider;
通过上面处理,最终App结构如下: