`
googlelee
  • 浏览: 114214 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

转载---AIDL

 
阅读更多

  欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要AIDL(以及Binder),那么可以默认你对这些概念已经有了一些了解,你(大致)知道它们是什么,它们有什么用,所以为了节约大家的眼力和时间,在此我不复制粘贴网上泛滥的博客或者翻译冗长的android文档。

      关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html

      关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html

      以及Binder:docs/reference/android/os/Binder.html

      在后文中,我将以我自己的理解向你介绍相关的概念。以我目前粗浅的经验,应用程序使用AIDL的地方,几乎都和Service有关,所以你也需要知道一些关于Service的知识。日后得闲我也会继续写一些关于Service的贴。

      本文将以一个例子来和你分享使用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中分别有对象需要用到它们定义的接口。

4、相关XML文件,略过。关于manifest中Service的语法,见docs/guide/topics/manifest/service-element.html。你也可以简单地在<application></application>中加入

     <service android:name=".mAIDLService" android:process=":remote"> </service>

开发环境为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.  * This file is auto-generated.  DO NOT MODIFY.  
  3.  * Original file: D://workspace//AIDLTest//src//com//styleflying//AIDL//forActivity.aidl  
  4.  */   
  5. package  com.styleflying.AIDL;  
  6. import  java.lang.String;  
  7. import  android.os.RemoteException;  
  8. import  android.os.IBinder;  
  9. import  android.os.IInterface;  
  10. import  android.os.Binder;  
  11. import  android.os.Parcel;  
  12. public   interface  forActivity  extends  android.os.IInterface  
  13. {  
  14. /** Local-side IPC implementation stub class. */   
  15. public   static   abstract   class  Stub  extends  android.os.Binder  implements  com.styleflying.AIDL.forActivity  
  16. {  
  17. private   static   final  java.lang.String DESCRIPTOR =  "com.styleflying.AIDL.forActivity" ;  
  18. /** Construct the stub at attach it to the interface. */   
  19. public  Stub()  
  20. {  
  21. this .attachInterface( this , DESCRIPTOR);  
  22. }  
  23. /**  
  24.  * Cast an IBinder object into an forActivity interface,  
  25.  * generating a proxy if needed.  
  26.  */   
  27. public   static  com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)  
  28. {  
  29. if  ((obj== null )) {  
  30. return   null ;  
  31. }  
  32. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  33. if  (((iin!= null )&&(iin  instanceof  com.styleflying.AIDL.forActivity))) {  
  34. return  ((com.styleflying.AIDL.forActivity)iin);  
  35. }  
  36. return   new  com.styleflying.AIDL.forActivity.Stub.Proxy(obj);  
  37. }  
  38. public  android.os.IBinder asBinder()  
  39. {  
  40. return   this ;  
  41. }  
  42. @Override   public   boolean  onTransact( int  code, android.os.Parcel data, android.os.Parcel reply,  int  flags)  throws  android.os.RemoteException  
  43. {  
  44. switch  (code)  
  45. {  
  46. case  INTERFACE_TRANSACTION:  
  47. {  
  48. reply.writeString(DESCRIPTOR);  
  49. return   true ;  
  50. }  
  51. case  TRANSACTION_performAction:  
  52. {  
  53. data.enforceInterface(DESCRIPTOR);  
  54. this .performAction();  
  55. reply.writeNoException();  
  56. return   true ;  
  57. }  
  58. }  
  59. return   super .onTransact(code, data, reply, flags);  
  60. }  
  61. private   static   class  Proxy  implements  com.styleflying.AIDL.forActivity  
  62. {  
  63. private  android.os.IBinder mRemote;  
  64. Proxy(android.os.IBinder remote)  
  65. {  
  66. mRemote = remote;  
  67. }  
  68. public  android.os.IBinder asBinder()  
  69. {  
  70. return  mRemote;  
  71. }  
  72. public  java.lang.String getInterfaceDescriptor()  
  73. {  
  74. return  DESCRIPTOR;  
  75. }  
  76. public   void  performAction()  throws  android.os.RemoteException  
  77. {  
  78. android.os.Parcel _data = android.os.Parcel.obtain();  
  79. android.os.Parcel _reply = android.os.Parcel.obtain();  
  80. try  {  
  81. _data.writeInterfaceToken(DESCRIPTOR);  
  82. mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0 );  
  83. _reply.readException();  
  84. }  
  85. finally  {  
  86. _reply.recycle();  
  87. _data.recycle();  
  88. }  
  89. }  
  90. }  
  91. static   final   int  TRANSACTION_performAction = (IBinder.FIRST_CALL_TRANSACTION +  0 );  
  92. }  
  93. public   void  performAction()  throws  android.os.RemoteException;  
  94. }  

文件forService.java:

两段代码差不多,前面基本一样,从后面看,最后跟着我们在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)。

欢迎阅读、收藏本文。例子随手写的,功能只在演示AIDL的使用。您可以转载本文,但请勿盲目乱贴。不是我小气,我不权威,我怕它被贴到泛滥,以讹传讹,害了人。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics