? ? mUnbind.setOnClickListener(this); ? ? ? ? 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则可以获 |