Android應用程序互保方案

在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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章