首先要声明,双进程保活,不是为了解决被杀之后复活的问题。因为在新版本的安卓上,这个办法已经不灵了(也许有人有更好的办法?)。这里介绍这个双进程保活,是为在电视盒子上的应用。如果进程死了,有的系统会自动启动,有的就不会。而有的应用在电视盒子上必须常在线。
本文实现方法,与其他介绍的原理一样,代码更加精练。为什么呢?因为使用了继承。
首先写一个AIDL:
package com.csdn; interface IKeepAliveServiceConnection { String getProcessName(); }
然后写一个父类:
package com.keepalive; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import com.newayte.nvideo.IKeepAliveServiceConnection; public abstract class KeepAliveService extends Service { private static final String TAG = KeepAliveService.class.getCanonicalName(); private static final String KEEP_ALIVE = "keep-alive"; private KeepAliveBinder mKeepAliveBinder; private KeepAliveServiceConnection mKeepAliveConnection; @Override public void onCreate() { super.onCreate(); if (mKeepAliveBinder == null) { mKeepAliveBinder = new KeepAliveBinder(); mKeepAliveConnection = new KeepAliveServiceConnection(); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { bindService(getConnectionIntent(), mKeepAliveConnection, Context.BIND_IMPORTANT); Log.d(TAG, "onStartCommand()"); /*PendingIntent contentIntent = PendingIntent.getService(this, 0, intent, 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setTicker("CSDN") .setContentIntent(contentIntent) .setContentTitle("TITLE") .setAutoCancel(true) .setContentText("CONTENT") .setWhen( System.currentTimeMillis()); //把service设置为前台运行 startForeground(startId, builder.build());*/ return START_STICKY; } @Override public IBinder onBind(Intent intent) { //子类如果跟其他进程绑定时,从父类得到的binder不为空,说明是从保活服务启动的。 Log.d(TAG, KEEP_ALIVE+"="+intent.getBooleanExtra(KEEP_ALIVE, false)+", "+intent); if (intent.getBooleanExtra(KEEP_ALIVE, false)) { return mKeepAliveBinder; } return null; } private Intent getConnectionIntent() { Intent intent = new Intent(KeepAliveService.this, getPeerService()); intent.putExtra(KEEP_ALIVE, true); return intent; } class KeepAliveBinder extends IKeepAliveServiceConnection.Stub { @Override public String getProcessName() throws RemoteException { return getServiceName(); } } class KeepAliveServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, getPeerService().getCanonicalName()+"建立连接成功!"); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, getPeerService().getCanonicalName()+"服务进程已死。重新启动并建立链接。"); //启动被干掉的 KeepAliveService.this.startService(getConnectionIntent()); KeepAliveService.this.bindService(getConnectionIntent(), mKeepAliveConnection, Context.BIND_IMPORTANT); } } /** * 这两个并不是必要的。 * 考虑到子类,还是要有点代码的。 * * @return */ protected abstract String getServiceName(); protected abstract Class<?> getPeerService(); }
子类服务助手(怎么样?使用了继承,极为简单吧):
package com.keepalive; public class AssistantServiceTv extends KeepAliveService { @Override protected String getServiceName() { return AssistantServiceTv.class.getCanonicalName(); } @Override protected Class<?> getPeerService() { return NetworkServiceTv.class; } }
主服务(注意onBind()的代码):
package com.keepalive; public class NetworkServiceTv extends KeepAliveService { @Override public IBinder onBind(Intent intent) { Log.d(TAG, "service onBind="+intent); IBinder binder = super.onBind(intent); if (null != binder) { return binder; } return mBinder; } @Override protected String getServiceName() { return NetworkServiceTv.class.getCanonicalName(); } @Override protected Class<?> getPeerService() { return AssistantServiceTv.class; } }
在NetworkServiceTv中负责联网。这样即使其中一个进程因错误崩溃,也可以被启动再次联网。