Android 使用MarsDaemon进程常驻

在特定的业务场景中,我们可能会需要app在后台做一些事情,比如上传数据之类的操作,并且希望这种操作及时在程序退出之后依然可以继续进行。因此也就理所当然的想到了使用Service进行处理。但是,在特定条件(app进入后台+设备内存不足+进程占用的内存足够大)的情况下,Service会非常容易在几分钟内被系统干掉,因此提高Service的存活率至关重要。

一种无效的做法

1
2
3
4
5
6
public void onDestroy() {
Log.e(TAG, "onDestory");
Intent intent = new Intent(this, Service.class);
startService(intent);
super.onDestroy();
}

此方法企图利用Service是生命周期去调用其本身,事实证明这种方法是无效的,在进程被杀死时,Service根本不会执行onDestroy就被直接清出内存了,因此靠自身的力量提高存活率的方式也就不可行了。

Marsdaemon

Github获取项目源码

导入项目之后
项目目录
之后不要忘记导入module

1
2
3
4
5
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile project(':LibMarsdaemon')
}

使用Marsdaemon

在manifest中声明2个进程分别包含一个Service和一个Receiver

此处将process1作为主要进程,process2作为守护进程。MainService中执行主要的业务逻辑,Receiver1、GuardService、Receiver2都是额外创建的,里面不要做任何事情,都是空实现就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--守护进程-->
<service
android:name=".ble.MainService"
android:enabled="true"
android:exported="true"
android:process=":process1" />
<receiver
android:name=".guard.Receiver1"
android:process=":process1" />
<service
android:name=".guard.GuardService"
android:process=":process2" />
<receiver
android:name=".guard.Receiver2"
android:process=":process2" />

处理Application

由于我们的Application一般都会集成其他的Application,因此需要在attachBaseContext中初始化DaemonClient,然后调用onAttachBaseContext即可实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class MyApplication extends XXXApplication {
private DaemonClient daemonClient;
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
daemonClient = new DaemonClient(getDaemonConfigurations());
daemonClient.onAttachBaseContext(base);
}
private DaemonConfigurations getDaemonConfigurations() {
DaemonConfigurations.DaemonConfiguration configuration1 =
new DaemonConfigurations.DaemonConfiguration(
"com.hemaapp.znsh:process1",
MainService.class.getCanonicalName(),
Receiver1.class.getCanonicalName());
DaemonConfigurations.DaemonConfiguration configuration2 =
new DaemonConfigurations.DaemonConfiguration(
"com.hemaapp.znsh:process2",
GuardService.class.getCanonicalName(),
Receiver2.class.getCanonicalName());
DaemonConfigurations.DaemonListener listener = new MyDaemonListener();
/*return new DaemonConfigurations(configuration1, configuration2);listener可以是null*/
return new DaemonConfigurations(configuration1, configuration2, listener);
}
private class MyDaemonListener implements DaemonConfigurations.DaemonListener {
@Override
public void onPersistentStart(Context context) {
}
@Override
public void onDaemonAssistantStart(Context context) {
}
@Override
public void onWatchDaemonDaed() {
}
}
}

处理其他Class

1
2
3
4
5
6
7
8
9
10
11
public class GuardService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
}
1
2
3
4
5
public class Receiver1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
1
2
3
4
5
6
public class Receiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}

使用

在Android4.4中

  • 手动Kill进程时,可以明显的在LogCat中看到Service被重新启动了,提高的Service的存活率。

    在Android5+中

  • 手动Kill进程时,Service不会被重新启动,Application依旧被彻底杀死了。
  • 小米2+Android5.0,长时间后台运行测试中,可以连续半小时以上不间断发送网络请求,效果明显。
  • 其他主流手机,由于大多配置了2G以上的内存,因此暂时没有看到Service被清理的现象发生。

后记

使用Marsdaemon提高Service存活率的方式虽然有一定效果,但是在Android5.0之后的版本中,并不可靠,并且还有如下几个缺陷。

  • 即使Service存活,Application中的信息不一定全部存在,这就会导致发送网络请求失败的情况发生,做了无用功。
  • 营造了一个恶劣的运行环境,这种方式也是Android所不提倡的。

因此,Marsdaemon不应是大家频繁使用的功能,特殊情况下可以应急即可。

文章目录
  1. 1. 一种无效的做法
  2. 2. Marsdaemon
    1. 2.1. 从Github获取项目源码
    2. 2.2. 使用Marsdaemon
      1. 2.2.1. 在manifest中声明2个进程分别包含一个Service和一个Receiver
      2. 2.2.2. 处理Application
      3. 2.2.3. 处理其他Class
    3. 2.3. 使用
      1. 2.3.1. 在Android4.4中
      2. 2.3.2. 在Android5+中
  3. 3. 后记
|