Android进程保活
进程划分
前台进程(Foreground process)
用户正在使用的程序,一般系统是不会杀死前台进程的,除非用户强制停止应用或者系统内存不足等极端情况会杀死。
可见进程(Visible process)
用户正在使用,看得到,但是摸不着,没有覆盖到整个屏幕,只有屏幕的一部分可见进程不包含任何前台组件,一般系统也是不会杀死可见进程的,除非要在资源吃紧的情况下,要保持某个或多个前台进程存活
服务进程(Service process)
在内存不足以维持所有前台进程和可见进程同时运行的情况下,服务进程会被杀死
后台进程(Background process)
系统可能随时终止它们,回收内存
空进程(Empty process)
常见保活手段
黑色保活:开启一像素Act,监测系统提供的广播
白色保活:启动前台Service
灰色保活:双进程互相唤起
黑色保活
开启一个像素的Activity
基本思想:系统一般是不会杀死前台进程的。所以要使得进程常驻,我们只需要在锁屏的时候在本进程开启一个Activity,为了欺骗用户,让这个Activity的大小是1像素,并且透明无切换动画,在开屏幕的时候,把这个Activity关闭掉,所以这个就需要监听系统锁屏广播。
创建1像素activity
public class LiveActivity extends Activity {
public static final String TAG = LiveActivity.class.getSimpleName();
public static void actionToLiveActivity(Context pContext) {
Intent intent = new Intent(pContext, LiveActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
pContext.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_live);
Window window = getWindow();
//放在左上角
window.setGravity(Gravity.START | Gravity.TOP);
WindowManager.LayoutParams attributes = window.getAttributes();
//宽高设计为1个像素
attributes.width = 1;
attributes.height = 1;
//起始坐标
attributes.x = 0;
attributes.y = 0;
window.setAttributes(attributes);
ScreenManager.getInstance(this).setActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
为了做的更隐藏,最好设置一下这个Activity的主题
<style name="LiveStyle">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowNoTitle">true</item>
</style>
在关闭屏幕的时候把LiveActivity开启,在关屏的时候把LiveActivity关闭。这个通过监听锁屏广播实现。
public class ScreenBroadcastListener {
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private ScreenStateListener mListener;
public ScreenBroadcastListener(Context context) {
mContext = context.getApplicationContext();
mScreenReceiver = new ScreenBroadcastReceiver();
}
interface ScreenStateListener {
void onScreenOn();
void onScreenOff();
}
/**
* screen状态广播接收者
*/
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏
mListener.onScreenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏
mListener.onScreenOff();
}
}
}
public void registerListener(ScreenStateListener listener) {
mListener = listener;
registerListener();
}
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mScreenReceiver, filter);
}
}
白色保活
开启前台服务
基本思想:前台服务相当于一个没有window的前台activity。所以回收几率会很低。只是会在通知栏有通知显示。
public class ForegroundService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Intent activityIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplication(), 0, activityIntent, 0);
Notification notification = new Notification.Builder(getApplication()).setAutoCancel(true).
setSmallIcon(R.drawable.ic_launcher).setTicker("前台Service启动").setContentTitle("前台Service运行中").
setContentText("这是一个正在运行的前台Service").setWhen(System.currentTimeMillis()).setContentIntent(pendingIntent).build();
startForeground(1, notification);
return START_STICKY;
}
}
public class MainActivity extends ActionBarActivity {
Button startService;
Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button)findViewById(R.id.start);
startService.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
intent = new Intent(MainActivity.this, ForegroundService.class);
startService(intent);
}
});
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
stopService(intent);
}
}
灰色保活手段
双进程唤起
思路:设计AB两个不同服务进程,A进程的服务轮询检查B进程的服务是否存活,没存活的话将其拉起,同样B进程服务轮询检查A进程服务是否存活,没存活的话也将其拉起
<service
android:name=".FirstService"
android:enabled="true"
android:exported="true"
android:process=":first"/>
<service
android:name=".SecondService"
android:enabled="true"
android:exported="true"
android:process=":secon"/>
<service
android:name=".ThirdService"
android:enabled="true"
android:exported="true"/>
public class FirstService extends Service {
private MyBinder binder; //绑定服务需要Binder进行交互
private MyConn conn;
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onCreate() {
super.onCreate();
binder = new MyBinder();
if(conn==null)
conn = new MyConn();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// 与SecondSevice绑定
FirstService.this.bindService(new Intent(this,SecondService.class),conn, Context.BIND_IMPORTANT);
}
//使用aidl实现进程通信
class MyBinder extends ProcessService.Stub{
@Override
public String getServiceName() throws RemoteException {
return "I am FirstService";
}
}
//建立相互绑定时的连接
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i("Info","与SecondService连接成功");
}
//在异常断开的回调方法进行拉起对方服务并绑定
@Override
public void onServiceDisconnected(ComponentName componentName) {
Toast.makeText(FirstService.this,"SecondService被杀死",Toast.LENGTH_SHORT).show();
// 启动FirstService
FirstService.this.startService(new Intent(FirstService.this,SecondService.class));
//绑定FirstService
FirstService.this.bindService(new Intent(FirstService.this,SecondService.class),conn, Context.BIND_IMPORTANT);
}
}
}
SecondService的设计和FirstService的设计差不多,都是在onStart中与对方相互绑定,在异常断开时重启对方并绑定。 SecondService多了一层服务进程提权设计(FirstService也可以加上这层设计)
public class SecondService extends Service {
private MyBinder binder;
private MyConn conn;
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onCreate() {
super.onCreate();
binder = new MyBinder();
if(conn==null)
conn = new MyConn();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
//创建通知栏
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
//显示通知栏,服务进程提权为前台服务。
startForeground(250, builder.build());//使用id:250标记该通知栏
// 启动第三个服务ThirdService来消除通知栏
startService(new Intent(this,ThirdService.class));
SecondService.this.bindService(new Intent(this,FirstService.class),conn, Context.BIND_IMPORTANT);
}
class MyBinder extends ProcessService.Stub{
@Override
public String getServiceName() throws RemoteException {
return "I am SecondService";
}
}
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i("Info","与FirtService连接成功"+SecondService.this.getApplicationInfo().processName);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Toast.makeText(SecondService.this,"FirstService被杀死",Toast.LENGTH_SHORT).show();
// 启动FirstService
SecondService.this.startService(new Intent(SecondService.this,FirstService.class));
//绑定FirstService
SecondService.this.bindService(new Intent(SecondService.this,FirstService.class),conn, Context.BIND_IMPORTANT);
}
}
}
public class ThirdService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 被启动后创建相互id的通知栏,并提权服务
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
startForeground(250, builder.build());
//开启新的线程消除通知栏
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(1000);
stopForeground(true);//停止前台
NotificationManager manager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(250); // 消除通知栏
stopSelf(); // 停止服务
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
最后在MainActivity或其他适当的地方启动FirstService和SecondService这两个服务:
this.startService(new Intent(this,FirstService.class));
this.startService(new Intent(this,SecondService.class));