Android类似小程序多开(多进程)实现方案
@(Android相关)
参考链接:
- 1 :微信小程序任务栈实现原理
- 2 :MMKV——基于 mmap 的高性能通用 key-value 组件
- 3 :HermesEventBus是一个基于EventBus的、能在进程间发送和接收event的库
[TOC]
微信小程序多进程实现探索
关于微信小程序多进程任务的实现可以查看微信小程序任务栈实现原理,里面通过adb命令来观察微信小程序启动时的进程情况
微信的小程序最多存在五个,通过adb命令查询进程得知这5个activity都是独立的页面,通过反编译工具jadx可知小程序确实add了5个独立的页面
创建可复用的activity
public static class Small0 extends CordovaMainActivity {
}
public static class Small1 extends CordovaMainActivity {
}
public static class Small2 extends CordovaMainActivity {
}
public static class Small3 extends CordovaMainActivity {
}
public static class Small4 extends CordovaMainActivity {
}
并设置activity的启动模式与进程独立,使之能够独立于主app进程运行,并且能够复用,代码如下
<activity
android:name="CordovaMainActivity$Small0"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:label="@string/activity_name"
android:launchMode="singleTask" //复用,防止重复加载
android:process=":Small0" //设置activity为独立的进程,能够存在与独立的窗口中
android:taskAffinity=".Small0"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</activity>
设置完这些之后activity就可以在独立的进程中运行,存在于独立的运行窗口中
进程间通讯
进程间通信可以用 HermesEventBus控件,其使用方法与 EventBus使用方法几乎相同,支持一个app多个进程通信,也支持多个app跨进程通信,其实用方式详见HermesEventBus是一个基于EventBus的、能在进程间发送和接收event的库
多进程数据缓存同步
然后是数据缓存,通常情况下数据缓存大多用Preference来缓存,但是Preference多进程时不安全的,次是我们需要用到腾讯开源缓存MMKV,MMKv支持多进程数据的缓存,不过在多个进程中修改同一条数据时不能实时更新,所以在多进程的使用方法中必须先清缓存再同步,即可获取到其他进程修改或添加的缓存数据
解决了进程通讯与数据缓存后就即可进程task的恢复,判断正在运行task运行数量等操作,
TASK的新建
可以再主进程的app内设立一个静态的map再存储当前正在运行的task即activity,可以是唯一标拾+完成类路径名,在跳转时判断当前的task运行数量以及都在运行的task都有哪些,并以此来判断时恢复task还是新建task
int id = Constant.map.size() % 4;
String className=Constant.map.get(indexList.get(position1).getReleasePk());//若map中已存在此标拾的任务,则直接启动此进程
if (!TextUtils.isEmpty(className)){
intent.setClassName(getActivity(), className);
}else {
//若不存在,则启动新的进程,这只是示例代码,具体启动哪个进程可以根据map缓存的task来判断
intent.setClassName(getActivity(), "com.morewise.mobile.ntalk.CordovaMainActivity$Small"+id);
}
相应的,我们的task里应该存在告诉主进程我已经被成功启用的消息,同样是通过HermesEventBus,来使主进程在缓存已经运行的task
HermesEventBus.getDefault().post(new MiniProgrammEvent(getIntent().getStringExtra("releasePk"), 1, getLocalClassName())); //这里的值为自己定义,我的定义为 参数1 唯一标识 参数2 状态(1添加 0 删除) 参数3 类路径
同样的,在task被销毁时,也要通知主进程把此任务从map缓存中移除
@Override
public void onDestroy() {
super.onDestroy();
HermesEventBus.getDefault().post(new MiniProgrammEvent(getIntent().getStringExtra("releasePk"), 0, getLocalClassName()));
}
由此,我们就可以来通过本地的map来进程复用或者新开了
主进程被杀场景
当然,前边说的只是其中的一种场景,我们还存在一种场景,就是主进程被杀了,但是我们独立出来的进程还在运行,这个时候再打开主进程时我们缓存的数据都没有了吗,就无法判断我们到底开了多少个task,这时需要再主进程被启动时通知正在运行的task,告诉他们我被启动了,你们谁都在运行,把数据和标拾发给我
HermesEventBus.getDefault().post(new CheckOkevent("1","1","1",true)); //启动时给子task发送消息,格式自定
在子task接收到主进程已经启动的消息后,需要返还自己的启动信息来让主进程做缓存
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void CordovaOk(CheckOkevent checkOkevent) {
if (checkOkevent.getData().equals("1")) {
HermesEventBus.getDefault().post(new MiniProgrammEvent(getIntent().getStringExtra("releasePk"), 1, getLocalClassName()));
}
}
//给主进程发消息,格式自定
这样,在无论是子进程被杀后,又被激活或者时主进程被杀后又被激活,都可以得到正确的task数据
手机重启场景
当然,还有一种极端情况,及我们的程序在运行过程中,手机重启了,这个时候再通过子多任务界面激活子进程,或发现程序直接gg,那微信小程序的表现是怎样的,通过测试得知,微信小程序在手机重启后也是可以在多任务界面看到重启前的小程序的,但是点击后就消失了,多任务栏也看不到了,可知小程序在无法还原数据时应该时直接把自身移除了,并且把自己从多任务栏中也已除了
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (TextUtils.isEmpty(getIntent().getStringExtra("logo"))) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else {
finish();
}
return;
}
}
没错,就是通过判断数据是否还存在,值接调用finishAndRemoveTask() 来实现上文所说的效果,不过要注意的是这个api只在5.0以上的系统中有效
至此小程序的多开效果与复原基本就实现了,当然在具体的业务逻辑中可能还存在其他的问题,须在具体业务逻辑中解决