前言
最近利用多余时间接了一个呼叫器的工具类app单子,其中为了实现锁屏呼叫功能,采用了多种方式保活后台服务相结合从而实现该功能。由于不同的手机,不同的Android版本保活效果各有差异,所以在这里总结记录分享一下。
普通方案
1,利用onStartCommand重启(提高存活率)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return START_STICKY;
//return super.onStartCommand(intent, flags, startId);
}
2,利用onDestory里面重启服务(提高存活率)
@Override
public void onDestroy() {
Intent intent = new Intent(this, AliveService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,
"START_FORM_SELF");
startService(intent);
}
3,manifest中配置优先级(提高存活率)
<service
android:name=".MyService"
android:permission="true"
android:process="com.android.toeii.service">
</service>
4,利用前台化,提高进程优先级
4.1,利用Notification实现前台服务(提高存活率,需要考虑Notification兼容性)
public void onCreate() {
Notification notification = new Notification();
startForeground(1, notification);
}
4.2,监听熄屏创建1px桌面级窗口占用前台进程(提高存活率)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置1像素
Window window = getWindow();
window.setGravity(Gravity.LEFT | Gravity.TOP);
WindowManager.LayoutParams params = window.getAttributes();
params.x = 0;
params.y = 0;
params.height = 1;
params.width = 1;
window.setAttributes(params);
//结束该页面的广播
endReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(endReceiver, new IntentFilter("finish"));
//检查屏幕状态
checkScreen();
}
5,进程双开,相互唤醒 (拥有自启动权限时唤醒率很高,没权限则Android 5.0之后失效)
开启一个新线程,绑定Service之后,利用IPC唤醒。 具体实现可以参考这篇文章
另外思路,启动看门狗服务进行进程双开监控。这种方式比普通IPC唤醒更高效。
6,利用系统闹钟和定时器相关手段唤醒
6.1 AlarmManager(Android 6.0之后失效)
public void sendBroadcastReceiver(){
Intent intent = new Intent(AlarmController.this,
RepeatingAlarm.class);
PendingIntent sender = PendingIntent.getBroadcast(
AlarmController.this, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(
AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), 10 * 1000, sender);
}
@Override
public void onReceive(Context context, Intent intent) {
if (PushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())){
Log.i("tag","闹钟响了");
Intent intent = new Intent(this, MyService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,"START_FORM_SELF");
startService(intent);
}
}
6.2 利用JobScheduler实现JobService(拥有自启动权限时唤醒率很高,没权限则Android 7.0之后失效)
//注册JobScheduler调度任务后...
public class JobProtectService extends JobService {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent,flags,startId);
}
@Override
public boolean onStartJob(JobParameters params) {
Intent intent = new Intent(this, MyService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,
"START_FORM_SELF");
startService(intent);
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
进阶方案
1,通过监听系统级广播唤醒(Android 7.0之后失效)
2,通过Push推送唤醒(这里推荐厂商自家的推送,第三方推送到达率相比之下低一点)
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (PushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {
String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);
} else if (PushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
Intent intent = new Intent(this, MyService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,
"START_FORM_SELF");
startService(intent);
}
}
3,利用GPS机制唤醒 (系统自带或者第三方地图SDK都可以尝试)
public static void formListenerGetLocation(){
locationManager = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
//位置信息变化时触发
//这里检查Service是否需要唤醒(是否存活),然后进行唤醒。
checkService...
Intent intent = new Intent(this, MyService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,
"START_FORM_SELF");
startService(intent);
}
@Override
public void onStatusChanged(String provider, int status,Bundle extras) {
//GPS状态变化时触发
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
4,IM呼入方式唤醒
//收到IM呼入信息后...
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (IMInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
Intent intent = new Intent(this, MyService.class);
intent.putExtra(RecorderService.SERVICE_FIRST_START_KEY,
"START_FORM_SELF");
startService(intent);
}
}
其他方案
1,利用LowMemoryKiller重启应用唤醒
Android的Low Memory Killer基于Linux的OOM机制,在Linux中,内存是以页面为单位分配的,当申请页面分配时如果内存不足会通过以下流程选择bad进程来杀掉从而释放内存。
alloc_pages -> out_of_memory() -> select_bad_process() -> badness()
在Low Memory Killer中通过进程的oom_adj与占用内存的大小决定要杀死的进程,oom_adj越小越不容易被杀死。
2,添加为自定义系统服务
定义为系统服务之后,可以通过WindowManager调用。 具体实现可以参考这篇文章
3,利用系统漏洞唤醒
至此,保活方式总结完毕,可能还有更多我所不知道的黑科技方式实现吧,未来可能会一一挖掘和尝试。