在特定的业务场景中,我们可能会需要app在后台做一些事情,比如上传数据之类的操作,并且希望这种操作及时在程序退出之后依然可以继续进行。因此也就理所当然的想到了使用Service进行处理。但是,在特定条件(app进入后台+设备内存不足+进程占用的内存足够大)的情况下,Service会非常容易在几分钟内被系统干掉,因此提高Service的存活率至关重要。
一种无效的做法
public void onDestroy() {
Log.e(TAG, "onDestory");
Intent intent = new Intent(this, Service.class);
startService(intent);
super.onDestroy();
}
此方法企图利用Service是生命周期去调用其本身,事实证明这种方法是无效的,在进程被杀死时,Service根本不会执行onDestroy就被直接清出内存了,因此靠自身的力量提高存活率的方式也就不可行了。
Marsdaemon
- 项目地址:https://github.com/Marswin/MarsDaemon
- 原理分析:http://blog.csdn.net/marswin89/article/details/50917098
下面主要讲讲用法
从Github获取项目源码
导入项目之后
项目目录
之后不要忘记导入module
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都是额外创建的,里面不要做任何事情,都是空实现就好。
<!--守护进程-->
<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即可实现
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
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;
}
}
public class Receiver1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
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不应是大家频繁使用的功能,特殊情况下可以应急即可。
网友评论