关于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

view plain copy to clipboard print ?
  1. packagecom.styleflying.AIDL;
  2. interfaceforActivity{
  3. voidperformAction();
  4. }

文件:forService.aidl

view plain copy to clipboard print ?
  1. packagecom.styleflying.AIDL;
  2. importcom.styleflying.AIDL.forActivity;
  3. interfaceforService{
  4. voidregisterTestCall(forActivitycb);
  5. voidinvokCallBack();
  6. }

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

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

文件forActivity.java:

view plain copy to clipboard print ?
  1. /*
  2. *Thisfileisauto-generated.DONOTMODIFY.
  3. *Originalfile:D://workspace//AIDLTest//src//com//styleflying//AIDL//forActivity.aidl
  4. */
  5. packagecom.styleflying.AIDL;
  6. importjava.lang.String;
  7. importandroid.os.RemoteException;
  8. importandroid.os.IBinder;
  9. importandroid.os.IInterface;
  10. importandroid.os.Binder;
  11. importandroid.os.Parcel;
  12. publicinterfaceforActivityextendsandroid.os.IInterface
  13. {
  14. /**Local-sideIPCimplementationstubclass.*/
  15. publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.styleflying.AIDL.forActivity
  16. {
  17. privatestaticfinaljava.lang.StringDESCRIPTOR="com.styleflying.AIDL.forActivity";
  18. /**Constructthestubatattachittotheinterface.*/
  19. publicStub()
  20. {
  21. this.attachInterface(this,DESCRIPTOR);
  22. }
  23. /**
  24. *CastanIBinderobjectintoanforActivityinterface,
  25. *generatingaproxyifneeded.
  26. */
  27. publicstaticcom.styleflying.AIDL.forActivityasInterface(android.os.IBinderobj)
  28. {
  29. if((obj==null)){
  30. returnnull;
  31. }
  32. android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
  33. if(((iin!=null)&&(iininstanceofcom.styleflying.AIDL.forActivity))){
  34. return((com.styleflying.AIDL.forActivity)iin);
  35. }
  36. returnnewcom.styleflying.AIDL.forActivity.Stub.Proxy(obj);
  37. }
  38. publicandroid.os.IBinderasBinder()
  39. {
  40. returnthis;
  41. }
  42. @OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException
  43. {
  44. switch(code)
  45. {
  46. caseINTERFACE_TRANSACTION:
  47. {
  48. reply.writeString(DESCRIPTOR);
  49. returntrue;
  50. }
  51. caseTRANSACTION_performAction:
  52. {
  53. data.enforceInterface(DESCRIPTOR);
  54. this.performAction();
  55. reply.writeNoException();
  56. returntrue;
  57. }
  58. }
  59. returnsuper.onTransact(code,data,reply,flags);
  60. }
  61. privatestaticclassProxyimplementscom.styleflying.AIDL.forActivity
  62. {
  63. privateandroid.os.IBindermRemote;
  64. Proxy(android.os.IBinderremote)
  65. {
  66. mRemote=remote;
  67. }
  68. publicandroid.os.IBinderasBinder()
  69. {
  70. returnmRemote;
  71. }
  72. publicjava.lang.StringgetInterfaceDescriptor()
  73. {
  74. returnDESCRIPTOR;
  75. }
  76. publicvoidperformAction()throwsandroid.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. staticfinalintTRANSACTION_performAction=(IBinder.FIRST_CALL_TRANSACTION+0);
  92. }
  93. publicvoidperformAction()throwsandroid.os.RemoteException;
  94. }

文件forService.java:

+ expand source view plain copy to clipboard print ? ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

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

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

再看mAIDLActivity.java:

view plain copy to clipboard print ?
  1. packagecom.styleflying.AIDL;
  2. importandroid.app.Activity;
  3. importandroid.content.ComponentName;
  4. importandroid.content.Context;
  5. importandroid.content.Intent;
  6. importandroid.content.ServiceConnection;
  7. importandroid.os.Bundle;
  8. importandroid.os.IBinder;
  9. importandroid.os.RemoteException;
  10. importandroid.util.Log;
  11. importandroid.view.View;
  12. importandroid.view.View.OnClickListener;
  13. importandroid.widget.Button;
  14. importandroid.widget.Toast;
  15. publicclassmAIDLActivityextendsActivity{
  16. privatestaticfinalStringTAG="AIDLActivity";
  17. privateButtonbtnOk;
  18. privateButtonbtnCancel;
  19. privateButtonbtnCallBack;
  20. privatevoidLog(Stringstr){
  21. Log.d(TAG,"------"+str+"------");
  22. }
  23. privateforActivitymCallback=newforActivity.Stub(){
  24. publicvoidperformAction()throwsRemoteException
  25. {
  26. Toast.makeText(mAIDLActivity.this,"thistoastiscalledfromservice",1).show();
  27. }
  28. };
  29. forServicemService;
  30. privateServiceConnectionmConnection=newServiceConnection(){
  31. publicvoidonServiceConnected(ComponentNameclassName,
  32. IBinderservice){
  33. mService=forService.Stub.asInterface(service);
  34. try{
  35. mService.registerTestCall(mCallback);}
  36. catch(RemoteExceptione){
  37. }
  38. }
  39. publicvoidonServiceDisconnected(ComponentNameclassName){
  40. Log("disconnectservice");
  41. mService=null;
  42. }
  43. };
  44. @Override
  45. publicvoidonCreate(Bundleicicle){
  46. super.onCreate(icicle);
  47. setContentView(R.layout.main);
  48. btnOk=(Button)findViewById(R.id.btn_ok);
  49. btnCancel=(Button)findViewById(R.id.btn_cancel);
  50. btnCallBack=(Button)findViewById(R.id.btn_callback);
  51. btnOk.setOnClickListener(newOnClickListener(){
  52. publicvoidonClick(Viewv){
  53. Bundleargs=newBundle();
  54. Intentintent=newIntent(mAIDLActivity.this,mAIDLService.class);
  55. intent.putExtras(args);
  56. bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
  57. startService(intent);
  58. }
  59. });
  60. btnCancel.setOnClickListener(newOnClickListener(){
  61. publicvoidonClick(Viewv){
  62. unbindService(mConnection);
  63. //stopService(intent);
  64. }
  65. });
  66. btnCallBack.setOnClickListener(newOnClickListener(){
  67. @Override
  68. publicvoidonClick(Viewv)
  69. {
  70. try
  71. {
  72. mService.invokCallBack();
  73. }catch(RemoteExceptione)
  74. {
  75. //TODOAuto-generatedcatchblock
  76. e.printStackTrace();
  77. }
  78. }
  79. });
  80. }
  81. }

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

view plain copy to clipboard print ?
  1. packagecom.styleflying.AIDL;
  2. importandroid.app.Service;
  3. importandroid.content.Intent;
  4. importandroid.os.IBinder;
  5. importandroid.os.RemoteCallbackList;
  6. importandroid.os.RemoteException;
  7. importandroid.util.Log;
  8. publicclassmAIDLServiceextendsService{
  9. privatestaticfinalStringTAG="AIDLService";
  10. privateforActivitycallback;
  11. privatevoidLog(Stringstr){
  12. Log.d(TAG,"------"+str+"------");
  13. }
  14. @Override
  15. publicvoidonCreate(){
  16. Log("servicecreate");
  17. }
  18. @Override
  19. publicvoidonStart(Intentintent,intstartId){
  20. Log("servicestartid="+startId);
  21. }
  22. @Override
  23. publicIBinderonBind(Intentt){
  24. Log("serviceonbind");
  25. returnmBinder;
  26. }
  27. @Override
  28. publicvoidonDestroy(){
  29. Log("serviceondestroy");
  30. super.onDestroy();
  31. }
  32. @Override
  33. publicbooleanonUnbind(Intentintent){
  34. Log("serviceonunbind");
  35. returnsuper.onUnbind(intent);
  36. }
  37. publicvoidonRebind(Intentintent){
  38. Log("serviceonrebind");
  39. super.onRebind(intent);
  40. }
  41. privatefinalforService.StubmBinder=newforService.Stub(){
  42. @Override
  43. publicvoidinvokCallBack()throwsRemoteException
  44. {
  45. callback.performAction();
  46. }
  47. @Override
  48. publicvoidregisterTestCall(forActivitycb)throwsRemoteException
  49. {
  50. callback=cb;
  51. }
  52. };
  53. }

注意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)

更多相关文章

  1. Android 子线程修改UI方法对比
  2. Android SDK 2.2 下载安装方法
  3. Android 10 创建文件失败
  4. android 4.0 内核(3.0)编译方法
  5. 关于android中的各种路径对应的方法
  6. IntentService通过HandlerThread单独开启一个线程来处理所有Inte
  7. Android 获取IP地址的实现方法
  8. Android上下文对象Context
  9. Android pm命令使用方法

随机推荐

  1. 《Android Studio实用指南》12.18 文本搜
  2. 项目中平时遇到的小知识点集锦
  3. Android(安卓)PullToRefresh (ListView Gr
  4. Android 2.2 API demos -- Dialog
  5. android zxing 4.7.1横屏改竖屏 screenOr
  6. Android中的OpenSL ES是如何实现的?
  7. Android Handler理解
  8. Android2.2和2.3有什么区别
  9. 国内Android 市场调查
  10. Android EditText inputType与numeric属