进程保活的方式
- 安卓杀死进程的一些机制
- 保活的一些方式
- 一像素保活法
- 前台服务保活法
安卓杀死进程的一些机制
安卓中的进程主要分为以下五种:
1、前台进程
Foreground Process
2、可见进程
Visible Process
3、服务进程
Service Process
4、后台进程
Background Process
5、空进程
Empty Process
安卓的机制是在内存达到一定的阈值时就会杀死对应的等级进程。查看阈值的方法如下图(单位是4KB)。当然,这是在不同的定制系统上会有差异,手机厂商会修改该值。除了左数开始第五个之外,其他的都跟上面5个等级一一对应。如当内存小于 80640 * 4KB / 1024 = 315MB 时就会杀死空进程
保活的一些方式
一像素保活法
原理就是监听屏幕的状态,当锁屏的时候,启动一个一像素的 activity 这样进程就会变成前台进程,锁屏时就不会被杀掉。屏幕开启时则关闭该Activity。
1、首先需要在MainActivity中注册一个监听手机屏幕状态的广播监听:
//注册监听屏幕的广播
mOnepxReceiver = new OnePixelReceiver();
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");
registerReceiver(mOnepxReceiver, intentFilter);
2、监听到屏幕状态后的处理:
public class OnePixelReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { //屏幕关闭启动1像素Activity
Intent it = new Intent(context, OnePiexlActivity.class);
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(it);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { //屏幕打开 结束1像素
context.sendBroadcast(new Intent("finish"));
Intent main = new Intent(Intent.ACTION_MAIN);
main.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
main.addCategory(Intent.CATEGORY_HOME);
context.startActivity(main);
}
}
}
启动模式要为 FLAG_ACTIVITY_NEW_TASK ,不然最进任务能看到整个进程被一个activity覆盖。
3、创建一像素activity
public class OnePiexlActivity extends Activity {
private BroadcastReceiver endReceiver;
@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();
}
@Override
protected void onResume() {
super.onResume();
checkScreen();
}
/**
* 检查屏幕状态 isScreenOn为true 屏幕“亮”结束该Activity
*/
private void checkScreen() {
PowerManager pm = (PowerManager) OnePiexlActivity.this.getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
if (isScreenOn) {
finish();
}
}
}
同时要设置该activity为透明,不然又可能会被用户看见。
<style name="OnePixelActivity" parent="android:Theme.Holo.Light.NoActionBar">//无标题
<item name="android:windowIsTranslucent">true</item>//透明
</style>
<activity
android:name=".OnePiexlActivity"
android:screenOrientation="portrait"
android:excludeFromRecents="true"
android:theme="@style/OnePixelActivity"/>
android:excludeFromRecents=“true” 设置该activity栈不显示在最近任务列表中。
听说该方法已经不可用了。至于为什么我也不太清楚。可能已经被谷歌在新版系统上优化了吧。
缺点:一定要关闭屏幕才能保活。如果用户持续使用手机长达数小时。进程可能已经在后台被杀掉了。
前台服务保活法
原理就是启动一个前台服务。但是启动前台服务会在通知栏显示一个无法消除的通知。
启动前台服务的方法很简单,只要在服务的 onCreate方法中 调用 startForeground(int,Notification).。
不同版本的api 通知栏显示不同:
API < 18 通知图标不会显示。
API >= 18 && API < 26 可以启动双服务,绑定同样的ID,然后stop一个服务,通知图标就自然不会显示了。
API >= 26 后暂时没有方式能隐藏通知
public class MyService extends Service {
public static final int NOTIFICATION_ID=0x11;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN_MR2) {
startForeground(NOTIFICATION_ID, new Notification());
} else {
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(NOTIFICATION_ID, builder.build());
startService(new Intent(this, InnerService.class));
}
}
public static class InnerService extends Service{
@Override
public IBinder onBind(Intent intent) {
return null;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onCreate() {
super.onCreate();
//发送与上面服务中ID相同的Notification,然后将其取消并取消自己的前台显示
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(NOTIFICATION_ID, builder.build());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
stopForeground(true);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
stopSelf();
}
},100);
}
}
}