? ? ? ? mAdd.setOnClickListener(this);
? ? ? ? mMinus.setOnClickListener(this);
? ? }
? ? @Override
? ? protected void onStop() {
? ? ? ? super.onStop();
? ? ? ? unbind();
? ? }
? ? private void unbind(){
? ? ? ? if (binded){
? ? ? ? ? ? unbindService(mConnection);
? ? ? ? ? ? binded=false;
? ? ? ? }
? ? }
? ? @Override
? ? public void onClick(View v) {
? ? ? ? int id=v.getId();
? ? ? ? switch (id){
? ? ? ? ? ? case R.id.btn_bind:
? ? ? ? ? ? ? ? Intent intent=new Intent();
? ? ? ? ? ? ? ? intent.setAction("com.cqumonk.adil.calculate");
? ? ? ? ? ? ? ? bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.btn_unbind:
? ? ? ? ? ? ? ? unbind();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.btn_add:
? ? ? ? ? ? ? ? if(mCalculateAIDL!=null){
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? int res=mCalculateAIDL.add(3,3);
? ? ? ? ? ? ? ? ? ? ? ? txt_res.setText(res+"");
? ? ? ? ? ? ? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? Toast.makeText(this,"please rebind",Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.btn_minus:
? ? ? ? ? ? ? ? if(mCalculateAIDL!=null){
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? int res=mCalculateAIDL.minus(9,4);
? ? ? ? ? ? ? ? ? ? ? ? txt_res.setText(res+"");
? ? ? ? ? ? ? ? ? ? } catch (RemoteException e) {
? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? Toast.makeText(this,"please rebind",Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
? ? private ServiceConnection mConnection=new ServiceConnection() {
? ? ? ? @Override
? ? ? ? public void onServiceConnected(ComponentName name, IBinder service) {
? ? ? ? ? ? Log.e(TAG,"connect");
? ? ? ? ? ? binded=true;
? ? ? ? ? ? mCalculateAIDL=ICalculateAIDL.Stub.asInterface(service);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onServiceDisconnected(ComponentName name) {
? ? ? ? ? ? Log.e(TAG,"disconnect");
? ? ? ? ? ? mCalculateAIDL=null;
? ? ? ? ? ? binded=false;
? ? ? ? }
? ? };
}
当我们点击绑定按钮,观察日志:

点击加法和减法按钮,都可以完成计算并返回值。然后点击解绑按钮:

我们并未发现有连接断开的日志打印,这时候,我们继续点击加减法按钮,发现仍然可以完成计算功能,这又是为毛呢?我们看到unbind和destroy的日志打印,说明连接已经断开,service已经被销毁,但是我们返回的stub对象仍然是可以继续使用的。而并不是说service仍然在运行。
过程分析
首先,我们调用bindservice方法来启动了service:
一方面连接成功时调用了serviceConnection的onServiceConnected方法。我们从该方法中获取到一个Binder对象(注意,这个binder并不是我们在service中实现的那个哦。当service时本apk中的service时,这里返回的是同一个binder),我们通过此binder来与server进行通信。为了区分,我们称为clientBinder。
public void onServiceConnected(ComponentName name, IBinder service) {
? ? ? ? ? ? Log.e(TAG,"connect");
? ? ? ? ? ? binded=true;
? ? ? ? ? ? mCalculateAIDL= ICalculateAIDL.Stub.asInterface(service);? ? ?
}
? ? ? ? 另一方面,onBind方法返回了我们实现的Stub对象,其实也是一个Binder,用于和Client进行通信。(之前我们定义了一个aidl接口文件,并根据它生成了ICalculateAIDL接口。这个接口中有我们定义的两个方法以及一个静态抽象内部类Stub,它是一个Binder的子类。)我们来看一下Stub是如何定义的:
public static abstract class Stub extends android.os.Binder implements com.cqumonk.calculate.aidl.ICalculateAIDL
? ? ? ? 它继承了Binder类也实现了ICalculateAIDL接口,我们实现了定义的add和minus方法。我们仍然要强调一下它并不是clientBinder,在负责与clientBinder进行通信交互的同时,它也维护了service描述符与服务端service的映射。
? ? ? ? 我们在Client中的onServiceConnected里调用了stub对象的asInterface方法,并将之前得到的clientBinder传入:
public static com.cqumonk.calculate.aidl.ICalculateAIDL asInterface(android.os.IBinder obj) {
? ? ? ? ? ? if ((obj == null)) {
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? ? ? android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//根据包名获取本地实现的一个接口的实例,如果是本地service则可以获