看过的写的比较好的service之AIDL

本文将以一个例子来和你分享使用AIDL的基础技能,这个例子里有:

1、一个类mAIDLActivity,继承Activity。里面有三个按钮,text分别为StartService,StopService,CallbackTest。

2、一个类mAIDLService,继承Service。为了充分展示ADIL的功能,它做以下工作:当用户点击CallbackTest按钮时,从mAIDLActivity调用mAIDLService中的Stub 对象的一个方法invokCallBack(),而这个方法又会调用mAIDLActivity中Stub 对象的一个方法performAction(),这个方法在屏幕上显示一个toast。没什么意义,只是展示一下AIDL如何使用。

3、两个AIDL文件:forService.aidl和forActivity.aidl。对应名字,在Service和Activity中分别有对象需要用到它们定义的接口。

    

开发环境为Eclipse。

拣重要的先说,来看看aidl文件的内容:

文件:forActivity.aidl

 

  1. package com.styleflying.AIDL;  
  2. interface forActivity  
  3.     void performAction();  
  4.      
 

文件:forService.aidl

 

  1. package com.styleflying.AIDL;  
  2. import com.styleflying.AIDL.forActivity;  
  3. interface forService  
  4.     void registerTestCall(forActivity cb);  
  5.     void invokCallBack();  
  6.  
 

这两个文件和Java文件放置的地方一样,看包名。

在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。

文件forActivity.java:

 

  1.   
  2. package com.styleflying.AIDL;  
  3. import java.lang.String;  
  4. import android.os.RemoteException;  
  5. import android.os.IBinder;  
  6. import android.os.IInterface;  
  7. import android.os.Binder;  
  8. import android.os.Parcel;  
  9. public interface forActivity extends android.os.IInterface  
  10.  
  11.   
  12. public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forActivity  
  13.  
  14. private static final java.lang.String DESCRIPTOR "com.styleflying.AIDL.forActivity";  
  15.   
  16. public Stub()  
  17.  
  18. this.attachInterface(this, DESCRIPTOR);  
  19.  
  20.   
  21. public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)  
  22.  
  23. if ((obj==null))  
  24. return null;  
  25.  
  26. android.os.IInterface iin (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forActivity)))  
  28. return ((com.styleflying.AIDL.forActivity)iin);  
  29.  
  30. return new com.styleflying.AIDL.forActivity.Stub.Proxy(obj);  
  31.  
  32. public android.os.IBinder asBinder()  
  33.  
  34. return this;  
  35.  
  36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  37.  
  38. switch (code)  
  39.  
  40. case INTERFACE_TRANSACTION:  
  41.  
  42. reply.writeString(DESCRIPTOR);  
  43. return true;  
  44.  
  45. case TRANSACTION_performAction:  
  46.  
  47. data.enforceInterface(DESCRIPTOR);  
  48. this.performAction();  
  49. reply.writeNoException();  
  50. return true;  
  51.  
  52.  
  53. return super.onTransact(code, data, reply, flags);  
  54.  
  55. private static class Proxy implements com.styleflying.AIDL.forActivity  
  56.  
  57. private android.os.IBinder mRemote;  
  58. Proxy(android.os.IBinder remote)  
  59.  
  60. mRemote remote;  
  61.  
  62. public android.os.IBinder asBinder()  
  63.  
  64. return mRemote;  
  65.  
  66. public java.lang.String getInterfaceDescriptor()  
  67.  
  68. return DESCRIPTOR;  
  69.  
  70. public void performAction() throws android.os.RemoteException  
  71.  
  72. android.os.Parcel _data android.os.Parcel.obtain();  
  73. android.os.Parcel _reply android.os.Parcel.obtain();  
  74. try  
  75. _data.writeInterfaceToken(DESCRIPTOR);  
  76. mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0);  
  77. _reply.readException();  
  78.  
  79. finally  
  80. _reply.recycle();  
  81. _data.recycle();  
  82.  
  83.  
  84.  
  85. static final int TRANSACTION_performAction (IBinder.FIRST_CALL_TRANSACTION 0);  
  86.  
  87. public void performAction() throws android.os.RemoteException;  
  88.  

文件forService.java:

 

  1.   
  2. package com.styleflying.AIDL;  
  3. import java.lang.String;  
  4. import android.os.RemoteException;  
  5. import android.os.IBinder;  
  6. import android.os.IInterface;  
  7. import android.os.Binder;  
  8. import android.os.Parcel;  
  9. public interface forService extends android.os.IInterface  
  10.  
  11.   
  12. public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService  
  13.  
  14. private static final java.lang.String DESCRIPTOR "com.styleflying.AIDL.forService";  
  15.   
  16. public Stub()  
  17.  
  18. this.attachInterface(this, DESCRIPTOR);  
  19.  
  20.   
  21. public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)  
  22.  
  23. if ((obj==null))  
  24. return null;  
  25.  
  26. android.os.IInterface iin (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService)))  
  28. return ((com.styleflying.AIDL.forService)iin);  
  29.  
  30. return new com.styleflying.AIDL.forService.Stub.Proxy(obj);  
  31.  
  32. public android.os.IBinder asBinder()  
  33.  
  34. return this;  
  35.  
  36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  37.  
  38. switch (code)  
  39.  
  40. case INTERFACE_TRANSACTION:  
  41.  
  42. reply.writeString(DESCRIPTOR);  
  43. return true;  
  44.  
  45. case TRANSACTION_registerTestCall:  
  46.  
  47. data.enforceInterface(DESCRIPTOR);  
  48. com.styleflying.AIDL.forActivity _arg0;  
  49. _arg0 com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());  
  50. this.registerTestCall(_arg0);  
  51. reply.writeNoException();  
  52. return true;  
  53.  
  54. case TRANSACTION_invokCallBack:  
  55.  
  56. data.enforceInterface(DESCRIPTOR);  
  57. this.invokCallBack();  
  58. reply.writeNoException();  
  59. return true;  
  60.  
  61.  
  62. return super.onTransact(code, data, reply, flags);  
  63.  
  64. private static class Proxy implements com.styleflying.AIDL.forService  
  65.  
  66. private android.os.IBinder mRemote;  
  67. Proxy(android.os.IBinder remote)  
  68.  
  69. mRemote remote;  
  70.  
  71. public android.os.IBinder asBinder()  
  72.  
  73. return mRemote;  
  74.  
  75. public java.lang.String getInterfaceDescriptor()  
  76.  
  77. return DESCRIPTOR;  
  78.  
  79. public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException  
  80.  
  81. android.os.Parcel _data android.os.Parcel.obtain();  
  82. android.os.Parcel _reply android.os.Parcel.obtain();  
  83. try  
  84. _data.writeInterfaceToken(DESCRIPTOR);  
  85. _data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));  
  86. mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);  
  87. _reply.readException();  
  88.  
  89. finally  
  90. _reply.recycle();  
  91. _data.recycle();  
  92.  
  93.  
  94. public void invokCallBack() throws android.os.RemoteException  
  95.  
  96. android.os.Parcel _data android.os.Parcel.obtain();  
  97. android.os.Parcel _reply android.os.Parcel.obtain();  
  98. try  
  99. _data.writeInterfaceToken(DESCRIPTOR);  
  100. mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);  
  101. _reply.readException();  
  102.  
  103. finally  
  104. _reply.recycle();  
  105. _data.recycle();  
  106.  
  107.  
  108.  
  109. static final int TRANSACTION_registerTestCall (IBinder.FIRST_CALL_TRANSACTION 0);  
  110. static final int TRANSACTION_invokCallBack (IBinder.FIRST_CALL_TRANSACTION 1);  
  111.  
  112. public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;  
  113. public void invokCallBack() throws android.os.RemoteException;  
  114.  

两段代码差不多,前面基本一样,从后面看,最后跟着我们在AIDL中自定义的方法,没有实现。两个文件各定义一个了接口,这两个接口分别会在Activity和Service中使用,在那里我们将实现自定义的方法。两个接口中都定义了一个抽象类Stub,实现所在的接口。Stub中又有一个类Proxy。Stub中有一个static的asInterface()方法,里面有很多return语句,在mAIDLActivity中调用它时,它返回一个新创建的内部类Proxy对象。

这个Stub对我们来说很有用,它继承了Binder。Binder有什么用呢?一个类,继承了Binder,那么它的对象就可以被远程的进程使用了(前提是远程进程获取了这个类的对象【对象的引用】,至于如如何获得看下文),在本例中就是说,如果一个Service中有一个继承了Stub的类的对象,那么这个对象中的方法就可以在Activity中使用,对Activity也是这样。至于Binder的细节,网上有很多贴介绍,看不明白也不影响我们完成这个例子。

再看mAIDLActivity.java:

 

  1. package com.styleflying.AIDL;  
  2. import android.app.Activity;  
  3. import android.content.ComponentName;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.content.ServiceConnection;  
  7. import android.os.Bundle;  
  8. import android.os.IBinder;  
  9. import android.os.RemoteException;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.view.View.OnClickListener;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15. public class mAIDLActivity extends Activity  
  16.     private static final String TAG "AIDLActivity";  
  17.     private Button btnOk;  
  18.     private Button btnCancel;  
  19.     private Button btnCallBack;  
  20.       
  21.     private void Log(String str)  
  22.         Log.d(TAG, "------ str "------");  
  23.          
  24.       
  25.     private forActivity mCallback new forActivity.Stub()  
  26.         public void performAction() throws RemoteException  
  27.          
  28.             Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();  
  29.          
  30.         };  
  31.           
  32.     forService mService;  
  33.     private ServiceConnection mConnection new ServiceConnection()  
  34.         public void onServiceConnected(ComponentName className,  
  35.                 IBinder service)  
  36.             mService forService.Stub.asInterface(service);  
  37.             try  
  38.                 mService.registerTestCall(mCallback);}  
  39.             catch (RemoteException e)  
  40.                   
  41.              
  42.              
  43.         public void onServiceDisconnected(ComponentName className)  
  44.             Log("disconnect service");  
  45.             mService null;  
  46.              
  47.         };  
  48.     @Override  
  49.     public void onCreate(Bundle icicle)  
  50.         super.onCreate(icicle);  
  51.         setContentView(R.layout.main);  
  52.         btnOk (Button)findViewById(R.id.btn_ok);  
  53.         btnCancel (Button)findViewById(R.id.btn_cancel);  
  54.         btnCallBack (Button)findViewById(R.id.btn_callback);  
  55.         btnOk.setOnClickListener(new OnClickListener()  
  56.             public void onClick(View v)  
  57.                 Bundle args new Bundle();  
  58.                 Intent intent new Intent(mAIDLActivity.this, mAIDLService.class);  
  59.                 intent.putExtras(args);  
  60.                 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  61.                 startService(intent);  
  62.                  
  63.             });  
  64.         btnCancel.setOnClickListener(new OnClickListener()  
  65.             public void onClick(View v)  
  66.                 unbindService(mConnection);  
  67.                 //stopService(intent);   
  68.                  
  69.             });  
  70.         btnCallBack.setOnClickListener(new OnClickListener()  
  71.               
  72.             @Override  
  73.             public void onClick(View v)  
  74.              
  75.                 try  
  76.                  
  77.                     mService.invokCallBack();  
  78.                 catch (RemoteException e)  
  79.                  
  80.                     // TODO Auto-generated catch block   
  81.                     e.printStackTrace();  
  82.                  
  83.              
  84.         });  
  85.          
  86.  

 

很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:

 

  1. package com.styleflying.AIDL;  
  2. import android.app.Service;  
  3. import android.content.Intent;  
  4. import android.os.IBinder;  
  5. import android.os.RemoteCallbackList;  
  6. import android.os.RemoteException;  
  7. import android.util.Log;  
  8. public class mAIDLService extends Service  
  9.     private static final String TAG "AIDLService";    
  10.     private forActivity callback;  
  11.     private void Log(String str)  
  12.         Log.d(TAG, "------ str "------");  
  13.      
  14.     @Override  
  15.     public void onCreate()  
  16.         Log("service create");  
  17.      
  18.     @Override  
  19.     public void onStart(Intent intent, int startId)  
  20.         Log("service start id=" startId);  
  21.      
  22.       
  23.     @Override  
  24.     public IBinder onBind(Intent t)  
  25.         Log("service on bind");  
  26.         return mBinder;  
  27.      
  28.     @Override  
  29.     public void onDestroy()  
  30.         Log("service on destroy");  
  31.         super.onDestroy();  
  32.      
  33.     @Override  
  34.     public boolean onUnbind(Intent intent)  
  35.         Log("service on unbind");  
  36.         return super.onUnbind(intent);  
  37.      
  38.     public void onRebind(Intent intent)  
  39.         Log("service on rebind");  
  40.         super.onRebind(intent);  
  41.      
  42.     private final forService.Stub mBinder new forService.Stub()  
  43.         @Override  
  44.         public void invokCallBack() throws RemoteException  
  45.          
  46.             callback.performAction();  
  47.               
  48.          
  49.         @Override  
  50.         public void registerTestCall(forActivity cb) throws RemoteException  
  51.          
  52.             callback cb;  
  53.               
  54.          
  55.           
  56.     };  
  57.  

注意onBind(),它的返回类型为IBinder,返回了一个mBinder,看看mBinder的定义:

    private final forService.Stub mBinder = new forService.Stub() {

        @Override
        public void invokCallBack() throws RemoteException
        {
            callback.performAction();
         }

        @Override
        public void registerTestCall(forActivity cb) throws RemoteException
        {
            callback = cb;

        }

       };

它是实现了我们在AIDL中定义的方法,这个mBinder最终返回给了mAIDLActivity中的mService,于是在mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一个类似mBinder的对象,看看定义:   

        private forActivity mCallback = new forActivity.Stub()

    {
        public void performAction() throws RemoteException
        {
            Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();
        }
      };

我们要在界面上显示一个toast,就是在这里实现的。这个对象,在mConnection的onServiceConnected()被调用时,通过调用mService(也就是远程的mAIDLService中的mBinder)的registerTestCall(),传递给了mAIDLService,于是在mAIDLService中可以调用performAction()了。

做一个大致总结,我们使用AIDL是要做什么呢:

让Acticity(或者说一个进程/一个类?)和Service(或者说远端进程/远端类/对象?)获取对方的一个Stub对象,这个对象在定义时实现了我们在AIDL中定义的方法,于是这些远程对象中的方法可以在本地使用了。如果这种使用(通信)是单向的,比如只是Activity需要通知Service做什么,那么只要Service中有一个Stub对象,并且传给Acticity就够了。

至于如何获得远程的Stub,参看上面的代码,看mConnection、registerTestCall、onRebind,它们展示了一种方法。

另外,有时候我们可能在一个类中有多个Stub对象,它们都要给远程交互的类的实例,这个时候可以考虑使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值