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