前言
遥想当年,博主铭记在心的一件事,就是曾做过让我加快秃顶的功能——健步活动。我们知道,在Android4.4之后的版本中,Android在硬件中支持内置计步传感器,例如微信运动等软件都是调用了Android中的Sensor.TYPE_STEP_COUNTER传感器服务,从而获取到每日的步数。
由于当时用户手机版本普遍偏低,因此需要手写记步。当时好在机智如我,参考了微信摇一摇的原理,通过加速度传感器SENSOR_TYPE_LINEAR_ACCELERATION获取到在某个时间段的加速度值,最后通过一顿计算公式得出步数。但是不同机型的加速度值并不相同,而且超级耗电。而最难的问题,就是应用特别容易被杀死,因为内存和电量耗损大,当应用在后台运行会优先被系统回收,而且用户手动一键清理时杀死进程,导致无法记步。
一、常见的应用保活方法
1、 监听广播方式
通过监听全局的静态广播,如开机广播、解锁屏广播、网络状态广播等,来启动应用的后台服务。目前,在高版本的Android系统中已经失效,因为Android系统规定应用必须在系统开机后运行一次才能监听这些系统广播,一般应用进程被杀死,广播也接收不到。
2、 提高Service的优先级
提高Service优先级方法很多,比如onStartCommand返回START_STICKY使系统内存足够的时候Service能够自动启动、弹出通知、配置service的优先级等,这些方式只能在一定程度上缓解service被立马回收,但只要用户一键清理或者系统回收照样无效。
3、 双service拉起
经过测试,只要当前应用被杀,任何后台service都无法运行,也无法拉起。
4、双进程拉起
这种方式使用NDK在底层fork出一个子进程,来实现与父进程之间的互拉。在Android4.x还是非常有效的,但是高版本的Android系统的系统回收策略已经改成进程组的形式了,如果系统要回收一个应用,必然会杀死同属于一个进程组的所有进程导致双进程无法拉起。
5、Wake_Lock
系统为了节省电量,CPU在没有任务忙的时候就会自动进入休眠,有任务需要唤醒CPU高效执行的时候,就会给CPU加Wake_Lock锁。
Wake Lock是Android框架层提供的一套锁的机制,应用使用该机制可以达到控制系统无法进入休眠,cpu的保持运行。意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。
当手机灭屏状态下保持一段时间后,系统会进入休眠,一些后台运行的任务就可能得不到正常执行,比如网络下载中断,后台播放音乐暂停,再比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。WakeLock正是为了解决这类问题,应用只要申请了WakeLock,那么在释放WakeLock之前,系统不会进入休眠,即使在灭屏的状态下,应用要执行的任务依旧不会被系统打断。所以微信里面是有大量使用到了Wake_Lock锁。
但是用wake唤醒CPU持续来工作是会造成耗电的,记得在合适的业务情况下释放Wake_Lock。
二、多进程音频保活方案
综上所述,上面的方法只是提高了APP后台运行存留能力,在用户不主动清理或强杀的情况下,测试APP的保活效果还是非常不错的。但是,"咕咚"在点击一键清理时奇妙的活了下来,原因是在后台循环播放一段无声音乐。如下图:
代码如下:
public class PlayerMusicService extends Service {
private final static String TAG = "PlayerMusicService";
private MediaPlayer mMediaPlayer;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.silent);
mMediaPlayer.setLooping(true);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
startPlayMusic();
}
}).start();
return START_STICKY;//注释1
}
private void startPlayMusic(){
if(mMediaPlayer != null){
mMediaPlayer.start();
}
}
private void stopPlayMusic(){
if(mMediaPlayer !=