在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);
}