在android系统中,到内存不足时系统会主动杀死那些占用内存较多的应用程序,另外像手机管家这种软件也会杀死我们的应用程序。可是由于业务的需求,我们需要应用程序一直在后台运行而不被干掉,因此需要一套可靠的解决方案来实现。
看过网上的不少博客,主要说的都是通过双进程守护,提高service优先级,或者将应用搞成系统级别应用,来实现应用长期在后台运行的效果。这些方案或多或少都有一些缺陷。在此,提出另外一种方案解决这一问题,经过测试,就算被小米管家杀死,也可以立即启动。
**
原理
**
我们知道,在安卓中是使用binder机制来实现rpc通信的,而不同进程之间service的交互也是依靠binder机制来完成的。
当服务端的binder对象因为种种原因意外死亡时,服务端与客户端之间的连接就会断开,这时候,binder对象会发出一条死亡通知,我们可以监听binder对象的死亡通知,并做一些相应的处理(比如重启应用)
通过调用Binder对象的linkToDeath方法,注册该binder对象的死亡监听;unlinkToDeath方法注销监听。
当binder对象死亡时,会调用DeathRecipient类对象的binderDied函数。
**
代码示例
**
创建两个项目app1和app2,在app1和app2中分别声明各自用于与对方发起IPC的interface,
app1和app2中各自构造Service(扩展至android.app.Service)且在Service这个上下文中各自bind到彼此。
籍由Binder机制的便利,app1或app2被杀死,都会通过DeathRecipient接口来告知对方。在这个可被认为实时的通知中,对方便可以辗转通过bind操作来唤醒自己。
特点:不用轮询,且能实时对对方app的消亡做出保活。兼具不拖累性能和反应的及时性
app1
AppService1.java app1的服务
public class AppService1 extends Service {
protected static final String TAG = "App1";
private final IAppSvc1.Stub mBinder = new IAppSvc1.Stub() {
@Override
public void getMessage(String message) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "getMessage() is invoked!");
}
};
IAppSvc2 appSvc2;
ServiceConnection svcConn;
private ServiceConnection createConnection(boolean forceCreate) {
if (!forceCreate && svcConn != null) {
return svcConn;
}
return svcConn = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can
// use to call on the service
appSvc2 = IAppSvc2.Stub.asInterface(service);
try {
appSvc2.asBinder().linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
handler.post(new Runnable() {
@Override
public void run() { Toast.makeText(AppService1.this, "App 2挂了,紧急唤醒中……", Toast.LENGTH_SHORT).show();
}
});
handler.postDelayed(new Runnable() {
@Override
public void run() {
//唤醒应用程序app2
wakeupApp2(true);
}
}, 1000);
}
}, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
// Called when the connection with the service disconnects
// unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "App1 Service has unexpectedly disconnected");
appSvc2 = null;
}
};
}
private void wakeupApp2(boolean forceCreate) {
final Intent intent = new Intent("From App 1");
intent.setComponent(new ComponentName("com.example.app2", "com.example.app2.AppService2"));
bindService(intent, createConnection(forceCreate), Context.BIND_AUTO_CREATE);
}
Handler handler = new Handler();
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.d(TAG, "onCreate() is invoked!");
Toast.makeText(AppService1.this, "App 1已被唤醒!", Toast.LENGTH_SHORT).show();
wakeupApp2(true);
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
wakeupApp2(false);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
}
IAppSvc1.aidl 仅仅用来做演示
package com.example.common;
interface IAppSvc1 {
void getMessage(String msg);
}
appService2.java app2的服务
public class AppService2 extends Service {
protected static final String TAG = "App2";
private final IAppSvc2.Stub mBinder = new IAppSvc2.Stub() {
@Override
public void getMessage(String msg) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "app 2, getMessage() is invoked!");
}
};
IAppSvc1 appSvc1;
ServiceConnection svcConn;
private ServiceConnection createConnection(boolean forceCreate) {
if (!forceCreate && svcConn != null) {
return svcConn;
}
return svcConn = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
appSvc1 = IAppSvc1.Stub.asInterface(service);
try {
appSvc1.asBinder().linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
// TODO Auto-generated method stub
handler.post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(AppService2.this, "App 1挂了,紧急唤醒中……", Toast.LENGTH_SHORT).show();
}
});
handler.postDelayed(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
wakeupApp1(true);
}
}, 1000);
}
}, 0);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "App1 Service has unexpectedly disconnected");
appSvc1 = null;
}
};
}
Handler handler = new Handler();
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.d(TAG, "app 2, onCreate() is invoked!");
wakeupApp1(true);
Toast.makeText(AppService2.this, "App 2已被唤醒!", Toast.LENGTH_SHORT).show();
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
wakeupApp1(false);
}
private void wakeupApp1(boolean forceCreate) {
final Intent intent = new Intent("From App 2");
intent.setComponent(new ComponentName("com.example.app1", "com.example.app1.AppService1"));
bindService(intent, createConnection(forceCreate), Context.BIND_AUTO_CREATE);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
}
IAppSvc2.aidl 仅仅用来做演示
package com.example.common;
interface IApp2Svc {
void getMessage(String msg);
}