`
mmdev
  • 浏览: 12892231 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

android进程间通信:使用AIDL android进程间通信:使用AIDLview plaincopyview plaincopyview plaincopy+ expand sourceview plaincopyview plaincopyview plaincopy

 
阅读更多

android进程间通信:使用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. packagecom.styleflying.AIDL;
  2. interfaceforActivity{
  3. voidperformAction();
  4. }

文件:forService.aidl

  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:

  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:

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

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

再看mAIDLActivity.java:

  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:

  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)。

欢迎阅读、收藏本文。例子随手写的,功能只在演示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. packagecom.styleflying.AIDL;
  2. interfaceforActivity{
  3. voidperformAction();
  4. }

文件:forService.aidl

  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:

  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:

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

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

再看mAIDLActivity.java:

  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:

  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)。

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics