2,aidl回调
上面服务端ExampleService.java类做了简单的回调,存在很多bug,其实android系统已经包装了aidl的回调,使用了RemoteCallbackList.java类。
重新修改的服务端ExampleService.java如下,
package com.android.exampleservice;
import android.app.Service;
import android.os.Bundle;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteCallbackList;
import com.android.aidl.IObdData;
import com.android.aidl.ICallback;
public class ExampleService extends Service {
private static String TAG = "ExampleService ";
private ICallback mICallback;
private final RemoteCallbackList<ICallback> mRemoteCallbacks = new RemoteCallbackList<ICallback>();
@Override
public void onCreate() {
Log.d(TAG,"ExampleService: onCreate ");
}
private IObdData.Stub mDataBinder = new IObdData.Stub() {
@Override
public String getData(String sr){
Log.d(TAG,"IObdData: getData " + sr);
return sr + "getData ";
}
@Override
public void sendMessage(String sr, ICallback mcallback){
Log.d(TAG,"IObdData: sendMessage " + sr);
mICallback = mcallback;
if (mcallback != null) {
mICallback = mcallback;
mRemoteCallbacks.register(mcallback);
}
Message msg = mHandler.obtainMessage();
msg.what = OUT_SEND;
mHandler.sendMessageDelayed(msg,5000);
}
};
public static final int OUT_SEND = 10;
public final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case OUT_SEND:
getResult("sendMessage success");
break;
}
}
};
private void getResult(String sa) {
final int N = mRemoteCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mRemoteCallbacks.getBroadcastItem(i).onGetResult(sa);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbacks.finishBroadcast();
mRemoteCallbacks.unregister(mICallback);
}
@Override
public IBinder onBind(Intent intent) {
return mDataBinder;
}
}
主要代码如下,
mRemoteCallbacks.register(mcallback);
private void getResult(String sa) {
final int N = mRemoteCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mRemoteCallbacks.getBroadcastItem(i).onGetResult(sa);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbacks.finishBroadcast();
mRemoteCallbacks.unregister(mICallback);
}
3, linkToDeath机制
服务端和客户端已经绑定了,当一个进程被kill的时候,另外一个进程是如何知道的呢?
这就要使用到Ibinder的内部接口DeathRecipient了,该接口只有一个binderDied方法。
3.1服务端kill
服务端ExampleService进程kill了,客户端ExampleActivity进程如何知道呢?
在ExampleActivity的onServiceConnected中添加,
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
service.linkToDeath(deathHandle, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
•••
deathHandle是一个匿名DeathRecipient对象,
final DeathRecipient deathHandle = new DeathRecipient() {
@Override
public void binderDied() {
Log.d(TAG, "binder is died");
}
};
这样当服务端进程kill时,会回调客户端的binderDied方法。
例如,在ExampleService.java的onBind方法中手动将服务端的进程杀死。
@Override
public IBinder onBind(Intent intent) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
android.os.Process.killProcess(android.os.Process.myPid());
Log.d(TAG, "stopSelf");
//stopSelf();// 仅仅终止服务还是不行的,必须杀死进程。
}
}).start();
return mDataBinder;
}
服务端启动10s之后,就会杀死进程,然后客户端就会调用binderDied方法。
3.2客户端kill
客户端进程kill时,服务端是如何知道呢?
在3.1小节中,客户端持有服务端的Ibinder对象,在onServiceConnected方法中,然后才可以调用linkToDeath方法。
服务端如果想知道客户端进程何时kill,也必须持有客户端的Ibinder对象。
思路:在客户端将Ibinder对象通过aidl传到客户端。
1,在IObdData.aidl文件中添加一个方法,
void setBinder(IBinder mIBinder);
2,在客户端ExampleActivity.java获取Ibinder对象,调用setBinder方法。
private IBinder mBinder = new Binder();
在onServiceConnected中的try模块中添加,
mObdData.setBinder(mBinder);
3,在服务端ExampleService.java的IObdData.Stub中实现setBinder方法,
@Override
public void setBinder(IBinder mIBinder) throws RemoteException {
mClient = mIBinder;
mClient.linkToDeath(deathHandle, 0);
}
匿名DeathRecipient对象如下,
final DeathRecipient deathHandle = new DeathRecipient() {
@Override
public void binderDied() {
Log.d(TAG, "binder is died");
}
};
例如,在客户端绑定后,客户端进程杀死自己,服务端就会调用binderDied方法。
在客户端的ExampleActivity启动之后10s中杀死进程。
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
android.os.Process.killProcess(android.os.Process.myPid());
}
}).start();