APP诞生之初,用的是常见的分层结构设计, 这种架构简单、清晰并一直沿袭至今,随着业务的快速发展,业务模块越来越多,各个模块间相互引用,耦合越来越严重,因此做了第一版架构重构,对各模块进行拆分,多个模块并行开发,为了解决模块间相互依赖,模块间通信采用最简单的单进程路由架构。
单进程路由架构 使用简单,适合小型项目或者初期项目的开发。在持续了一段开发时间后,渐渐的它的单进程模型的弊端也越来越明显,由于代码、内存、apk大小都在增长,对系统资源的占用越来越多,导致进程容易被系统回收或导致内存溢出崩溃,如果不进行内存优化,将很快无法支撑整个业务的发展,此时将整体的应用架构转型为多进程迫在眉睫,独立的通信进程可以保持各个进程模块的稳定性,也可以阻隔一些内存泄露导致的问题。
实现方案
一. 目标&需求
- 接口调用简单
- 实现apt自动注册Provider、Action
- 进程间可以传递复杂数据
- 初始化建立进程间通信通道,避免对每次请求结果都要判断是否异步
- 添加缓存策略,避免重复请求
二. 技术选型
2.1 如何让接口调用简单?
使用建造者模式构建请求体,链式调用同时避免参数混乱
2.2 如何自定义注解注册来生成Provider,Action注册代码?
注解解析器: 使用官方推荐的AnnotationProcessor
代码自动生成: 使用JavaPoet库或JDK自带的JavaFileObject类
2.3 进程间如何通讯?
- 使用AIDL来做进程间的数据交换
- Boardcast发布进程间通知
2.5 进程间如何传递复杂数据?
有两种可选方案:
- 使用Binder支持的Parceable
- 使用Json格式String
使用String来传递数据有两个明显不足:
- 使用麻烦,需要在请求和返回时对数据进行解析
- 效率不如Parceable
所以选择Binder支持的Parceable来传递数据为最优方案。
三. 最终实现 MultiProcessRouter
Github项目地址:MultiProcessRouter
MultiProcessRouter是一个基于AnnotationProcessor实现的多进程路由框架,它支持注解注册接口、多进程间数据交互,可快速应用于项目多进程模块化。
使用说明
Gradle配置
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
allprojects {
repositories {
jcenter()
maven {
url 'https://dl.bintray.com/shamschu/maven'
}
}
}
apply plugin: 'com.neenbedankt.android-apt'
compile 'com.sc.framework:router:1.0.0'
compile 'com.sc.framework:annotation:1.0.0'
apt "com.sc.framework:compiler:1.0.0"
创建每个进程对应的LocalRouterService
LocalRouterService为本地Service(运行在每个单独进程中),用来进行进程间的AIDL通信,一般来说,你只要继承LocalRouterService,并且在你的AndroidMenifest中注册该Service并使用android:process指定它所在的进程名称即可。
public class ProcessService2 extends LocalRouterService {
}
<service
android:name=".ProcessService2"
android:process=":second"/>
初始化路由
在应用启动时调用:
Router.register(Context context, IRouterServiceRegister serviceRegister);
并实现IRouterServiceRegister的getServices()方法来返回每个进程对应的LocalRouterService映射列表。
例如您的应用有两个进程,一个主进程,一个名称为second的其他进程,那么调用如下所示:
Router.register(this, new IRouterServiceRegister() {
@Override
public Map<String, Class<? extends LocalRouterService>> getServices() {
Map<String, Class<? extends LocalRouterService>> services = new HashMap<>();
services.put(ProcessUtils.getMainProcess(TestApplication.this), ProcessService1.class);
services.put(ProcessUtils.getMainProcess(TestApplication.this) + ProcessUtils.COLON + "second", ProcessService2.class);
return services;
}
});
接收路由服务初始化完成广播
Router初始化时,动态注册InitializeCompleteReceiver,并实现onRouterServiceInitCompleted方法,它会在Router服务初始化完成后被触发,你可以在你应用的闪屏页Activity的onCreate中注册,并等待通知,通知成功后再进行app的下一步操作,一旦初始化完成,你可以任意的调用其他进程的接口。
public class SplashActivity extends AppCompatActivity {
private InitializeCompleteReceiver receiver;
private boolean mReceiverRegister = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// enter main activity if router service has been initialized
if (Router.checkRouterServiceInitCompleted(this)) {
startMainActivity();
return;
}
// register InitializeCompleteReceiver to receive router initialized broadcast.
if (!mReceiverRegister) {
receiver = new InitializeCompleteReceiver() {
@Override
protected void onRouterServiceInitCompleted() {
startMainActivity();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(InitializeCompleteReceiver.ACTION_ROUTER_SERVICE_COMPLETED);
registerReceiver(receiver, filter);
mReceiverRegister = true;
}
}
/**
* Start your main activity
*/
private void startMainActivity() {
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReceiverRegister) {
unregisterReceiver(receiver);
mReceiverRegister = false;
}
}
}
注册Provider
使用注解
@Provider(process = PROCESS_NAME)
PROCESS_NAME为Provider的进程名称。
@Provider(process = "com.shamschu.framework")
public class TestProvider extends RouterProvider {
@Override
public String getName() {
return "TestProvider";
}
}
注册Action
使用注解
@Action(provider = YOUR_PROVIDER.class)
YOUR_PROVIDER.class为Action所属的Provider的类。
@Action(provider = TestProvider.class)
public class TestAction extends RouterAction<String> {
@Override
public RouterResponse<String> invoke(Context context, RouterRequest request) {
return new RouterResponse.Builder<String>()
.result("this is a router test!")
.build();
}
}
创建请求
RouterRequest request = new RouterRequest.Builder()
.process("com.shamschu.framework") // 请求进程
.provider("TestProvider") // 请求进程提供的接口
.action("TestAction") // 请求接口提供的动作,
.cacheStrategy(CacheStrategy.FIXED) // 请求缓存策略 NONE: 不缓存,每次都重新获取 FIXED: 一旦请求后则缓存,不在重新发起请求
.build();
请求并获取结果
RouterResponse<String> response = Router.route(v.getContext(), request);
if (response.isSuccess()) {
Toast.makeText(SecondActivity.this, response.getResult(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(SecondActivity.this, response.getError(), Toast.LENGTH_LONG).show();
}
网友评论