service保活
在实际开发中,我们会遇到一些要求后台运行的service,但是现在Android手机型号太多,而且国内的系统都是各大厂商定制过得,加入了自己的一些优化设置(比如省电方面的)。造成的的问题是:当service在后台运行一段时间后,如果是比较耗电,会被系统kill,service里的逻辑操作也就停止了,对我们的业务造成困扰。那么该如何处理呢?
主要有2种方法:手动设置和代码设置混合使用
手动设置
在手机设置界面中,有锁屏保护和省电管理或者手机管家中的内存优化都要进行处理。
锁屏保护
在360F4手机中,在设置-->电池和省电-->锁屏受保护应用:选中我们自己的app,就想选中微信一样,如果不选中微信的话,锁屏30分钟后,微信也会被kill掉。不同的手机锁屏后kill掉app的时间是不同的,有的没有这一项设置,有的是几分钟,360F4手机是30分钟。见下图:
省电管理
手机管家
这类App一般都是系统自带的,都是品牌商自己的软件,为了时间省电优化,通常都会把后台运行的app杀死,而且权限还挺高。不过也有用于自己安装的,比如:360手机卫士、腾讯手机管家、猎豹清理大师等,各种app的优化设置不同,这里介绍几个常见的
360手机卫士
我-->设置-->清理加速-->内存加速优化名单-->把我们的app加入优化忽略名单中
OPPO手机管家
待定
代码设置
这也有2种方法:
- 给serviceA在配置一个守护它的serviceB,当我们的serviceA被杀死后,我们可以serviceB再重新开启A,
- 注册BroadcastReceiver,锁屏时获取“电源锁”,屏幕解锁是释放“电源锁”
增加一个守护的service
原理:在这个serviceB中开启一个Thread,每个1分钟查找正在运行的service,如果没有serviceA,那么久开启serviceA;如果有serviceA,那么就做处理。
public class MonitorService extends Service {
protected static boolean isCheck = false;
protected static boolean isRunning = false;
private static final String SERVICE_NAME = "com.cqc.walelock01.WakeLockService";
@Override
public void onCreate() {
Log.d("MonitorService2", "MonitorService onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MonitorService2", "MonitorService onStartCommand");
new Thread() {
@Override
public void run() {
while (isCheck) {
try {
Thread.sleep(5 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
Log.d("MonitorService2", "thread sleep failed" );
}
if (!isServiceWork(getApplicationContext(), SERVICE_NAME)) {
Log.d("MonitorService2", "WakeLockService轨迹服务已停止,正在重启轨迹服务");
startService(new Intent(MonitorService.this, WakeLockService.class));
} else {
Log.d("MonitorService2", "WakeLockService轨迹服务正在运行");
}
}
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 判断某个服务是否正在运行的方法
*
* @param mContext
* @param serviceName 是包名+服务的类名(例如:com.baidu.trace.LBSTraceService)
* @return true代表正在运行,false代表服务没有正在运行
*/
public boolean isServiceWork(Context mContext, String serviceName) {
boolean isWork = false;
ActivityManager myAM = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> myList = myAM.getRunningServices(80);
if (myList.size() <= 0) {
return false;
}
for (int i = 0; i < myList.size(); i++) {
String mName = myList.get(i).service.getClassName().toString();
if (mName.equals(serviceName)) {
isWork = true;
break;
}
}
return isWork;
}
}
WakeLock :电源锁
注册广播,当锁屏时获取电源锁,当屏幕解锁时释放电源锁,
public class TrackReceiver extends BroadcastReceiver {
private static final String TAG = "TrackReceiver";
@SuppressLint("Wakelock")
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
Log.d(TAG,"screen off,acquire wake lock!");
if (null != WakeLockService.wakeLock && !(WakeLockService.wakeLock.isHeld())) {
WakeLockService.wakeLock.acquire();
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
Log.d(TAG,"screen on,release wake lock!");
if (null != WakeLockService.wakeLock && WakeLockService.wakeLock.isHeld()) {
WakeLockService.wakeLock.release();
}
}
}
}
获取电源锁是需要权限的
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
第二个权限AS会红色提示“这是系统app需要的权限”,这是提示不是报错,添加上就可以了
BroadcastReceiver有2种注册方法:静态注册和动态注册。
我么这里采用动态注册的方法,原因是:
receiver应该跟随serviceA的生命周期,当serviceA被销毁后,将不再获取电源锁;service开启后,再根据屏幕的变化判断是获取还是释放电源锁
public class WakeLockService extends Service {
//cpu保活
private static boolean isRegister = false;
protected static PowerManager pm = null;
public static PowerManager.WakeLock wakeLock = null;
public static TrackReceiver trackReceiver = new TrackReceiver();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//动态注册
if (!isRegister) {
if (null == pm) {
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
}
if (null == wakeLock) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "track upload");
}
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(trackReceiver, filter);
isRegister = true;
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
if (isRegister) {
try {//销毁广播
unregisterReceiver(trackReceiver);
isRegister = false;
} catch (Exception e) {
}
}
}
}
这个service保活是从百度鹰眼官方Demo中提取的。
网址:http://lbsyun.baidu.com/index.php?title=android-yingyan/guide/tracelive
Demo: http://git.oschina.net/ServiceDemo/WakeLock01
其他相关:
Android的PowerManager和PowerManager.WakeLock用法简析
使用WakeLock使Android应用程序保持后台唤醒