一、前言
通常做通话和即时通讯应用,都存在app保活的问题,一旦切换到后台或者息屏时候,每个手机都会有不同程度对应用按优先级进行管理,按照优先级从低到高冻结(Freeze)和杀死(Kill)。但是通话和即时通讯应用被杀死之后,就无法及时收到通知进行通讯,这无疑是一个问题。
二、步骤
在网上查阅大量资料。无外乎以下几种方案:1.双进程守护;2.1像素保活;3.设置为前台应用;4.Jobscheduler执行任务调度。我个人觉得1和4在很多场景下都不太适合,不是什么应用能接受重启的机制。所以就把希望寄托1像素保活和设置前台应用。相关文章都有人点赞和收藏,但是这两种都试了,都达不到效果。因为不同的手机系统杀死后台应用的严厉程度不尽相同。后来我结合这两种方法,在我这个非常容易杀死后台应用的手机系统上实现了保活效果。以下是我的思路和步骤:
1、App保活的场景
(1)App切换后台之后玩其他应用;
(2)App在前台,直接息屏;
(3)App切换到后台之后,再息屏。
2、设置前台应用作为1像素保活的基础
3、在第一种场景下,可以显示1像素悬浮框的方式;第二种场景,可以和第三种场景一样,在息屏的时候都弹出一个1像素界面,在息屏的时候弹出,在亮屏的时候销毁。
4、代码部分:
(1)进入app,在service里注册亮屏息屏接收器,并显示1像素悬浮窗。
KeepAliveManager.getInstance().registerReceiver(this); //注册广播接收者
//注册主体代码
mHideFloatingView =new HideFloatingView(context);//1像素悬浮窗
mStateReceiver =new ScreenStateReceiver();
IntentFilter intentFilter =new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.USER_PRESENT");
mContext.registerReceiver(mStateReceiver, intentFilter);
mHideFloatingView.show(); //悬浮窗随应用启动直接显示
(2)在接收者里处理亮屏和黑屏的事件,息屏的时候,弹出1像素activity。
public class ScreenStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context,Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {//屏幕关闭启动1像素Activity
Log.i(TAG,"onReceive: 息屏");
mHideFloatingView.dismiss(); //息屏的时候1像素悬浮窗remove消失
startActivity(); //启动1像素activity界面
}else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {//屏幕打开 结束1像素
Log.i(TAG,"onReceive: 亮屏");
mHideFloatingView.show(); //亮屏1像素悬浮窗add显示,activity会在它自己的onResume里finish
}
}
}
public void startActivity() {
Intent it =new Intent(mContext,KeepAliveActivity.class);
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(it);
}
(3)1像素保活的基础,把service设置为前台服务。
if (Build.VERSION.SDK_INT <18) {//Android4.3以下版本
//将Service设置为前台服务,可以取消通知栏消息
startForeground(SERVICE_ID,new Notification());
Log.i(TAG,"onStartCommand: 111");
}else if (Build.VERSION.SDK_INT <24) {//Android4.3 - 7.0之间
Log.i(TAG,"onStartCommand: 222");
//将Service设置为前台服务,可以取消通知栏消息
startForeground(SERVICE_ID,new Notification());
startService(new Intent(this,InnerService.class));
}else {//Android 8.0以上
Log.i(TAG,"onStartCommand:333 ");
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
if (manager !=null) {
NotificationChannel channel =null;
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.O) {
channel =new NotificationChannel(CHANNEL_ID,"abc",NotificationManager.IMPORTANCE_NONE);
manager.createNotificationChannel(channel);
}
Notification notification =new NotificationCompat.Builder(this,CHANNEL_ID).build();
//将Service设置为前台服务,Android 8.0 App启动不会弹出通知栏消息,退出后台会弹出通知消息
//Android9.0启动时候会立刻弹出通知栏消息
startForeground(SERVICE_ID, notification);
}
}
public static class InnerService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent,int flags,int startId) {
Log.i(TAG,"onStartCommand: 99999999999999");
startForeground(SERVICE_ID,new Notification());
stopForeground(true);//移除通知栏消息
stopSelf();
return super.onStartCommand(intent,flags,startId);
}
}
三、结尾
至于怎么写1像素悬浮窗和1像素activity,大家可以留下邮箱,我把源码发给大家。
后话:
在android高版本上,息屏弹出1像素界面,会导致在亮屏的时候销毁应用所有activity。这个时候。我取消了对息屏和亮屏的监听,只弹出1像素悬浮栏。