Android AIDL Parcelable和远程服务.docx

上传人:b****5 文档编号:6438630 上传时间:2023-01-06 格式:DOCX 页数:11 大小:21.01KB
下载 相关 举报
Android AIDL Parcelable和远程服务.docx_第1页
第1页 / 共11页
Android AIDL Parcelable和远程服务.docx_第2页
第2页 / 共11页
Android AIDL Parcelable和远程服务.docx_第3页
第3页 / 共11页
Android AIDL Parcelable和远程服务.docx_第4页
第4页 / 共11页
Android AIDL Parcelable和远程服务.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

Android AIDL Parcelable和远程服务.docx

《Android AIDL Parcelable和远程服务.docx》由会员分享,可在线阅读,更多相关《Android AIDL Parcelable和远程服务.docx(11页珍藏版)》请在冰豆网上搜索。

Android AIDL Parcelable和远程服务.docx

AndroidAIDLParcelable和远程服务

      AIDL的作用

      由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。

在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。

  

      通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。

      AIDL(AndroidInterfaceDefinitionLanguage)是一种IDL语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocesscommunication,IPC)的代码。

如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。

      AIDLIPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。

它是使用代理类在客户端和实现端传递数据。

  

      选择AIDL的使用场合

      官方文档特别提醒我们何时使用AIDL是必要的:

只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。

      如果不需要进行不同应用程序间的并发通信(IPC),youshouldcreateyourinterfacebyimplementingaBinder;或者你想进行IPC,但不需要处理多线程的,则implementyourinterfaceusingaMessenger。

无论如何,在使用AIDL前,必须要理解如何绑定service——bindService。

    在设计AIDL接口前,要提醒的是,调用AIDL接口是直接的方法调用的,不是我们所想象的调用是发生在线程里。

而调用(call)来自local进程或者remote进程,有什么区别呢?

尤其是以下情况(引用原文,不作翻译了,以免翻译有误):

java代码:

1.Callsmadefromthelocalprocessareexecutedinthesamethreadthatismakingthecall.IfthisisyourmainUIthread,thatthreadcontinuestoexecuteintheAIDLinterface.Ifitisanotherthread,thatistheonethatexecutesyourcodeintheservice.Thus,ifonlylocalthreadsareaccessingtheservice,youcancompletelycontrolwhichthreadsareexecutinginit(butifthatisthecase,thenyoushouldn'tbeusingAIDLatall,butshouldinsteadcreatetheinterfacebyimplementingaBinder).

2.

3.Callsfromaremoteprocessaredispatchedfromathreadpooltheplatformmaintainsinsideofyourownprocess.Youmustbepreparedforincomingcallsfromunknownthreads,withmultiplecallshappeningatthesametime.Inotherwords,animplementationofanAIDLinterfacemustbecompletelythread-safe.

4.

5.Theonewaykeywordmodifiesthebehaviorofremotecalls.Whenused,aremotecalldoesnotblock;itsimplysendsthetransactiondataandimmediatelyreturns.TheimplementationoftheinterfaceeventuallyreceivesthisasaregularcallfromtheBinderthreadpoolasanormalremotecall.Ifonewayisusedwithalocalcall,thereisnoimpactandthecallisstillsynchronous.

复制代码

      定义AIDL接口

    AIDL接口文件,和普通的接口内容没有什么特别,只是它的扩展名为.aidl。

保存在src目录下。

如果其他应用程序需要IPC,则那些应用程序的src也要带有这个文件。

AndroidSDKtools就会在gen目录自动生成一个IBinder接口文件。

service必须适当地实现这个IBinder接口。

那么客户端程序就能绑定这个service并在IPC时从IBinder调用方法。

    每个aidl文件只能定义一个接口,而且只能是接口的声明和方法的声明。

    1.创建.aidl文件

    

      AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。

这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。

    其中对于Java编程语言的基本数据类型(int,long,char,boolean等),String和CharSequence,集合接口类型List和Map,不需要import语句。

    而如果需要在AIDL中使用其他AIDL接口类型,需要import,即使是在相同包结构下。

AIDL允许传递实现Parcelable接口的类,需要import.

  

    需要特别注意的是,对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

  AIDL只支持接口方法,不能公开static变量。

      例如(IMyService.aidl):

java代码:

1.packageeoe.demo;

2.

3.importcom.demo.Person;

4.

5.interfaceIMyService{

6.voidsavePersonInfo(inPersonperson);

7.ListgetAllPerson();

8.}

复制代码

      2.实现接口

      创建一个类实现刚才那个aidl的接口:

java代码:

1.publicclassRemoteServiceextendsService{

2.

3.privateLinkedListpersonList=newLinkedList();

4.

5.@Override

6.publicIBinderonBind(Intentintent){

7.returnmBinder;

8.}

9.

10.privatefinalIMyService.StubmBinder=newIMyService.Stub(){

11.

12.@Override

13.publicvoidsavePersonInfo(Personperson)throwsRemoteException{

14.if(person!

=null){

15.personList.add(person);

16.}

17.}

18.

19.@Override

20.publicListgetAllPerson()throwsRemoteException{

21.returnpersonList;

22.}

23.};

24.}

复制代码

      这里会看到有一个名为IMyService.Stub类,查看aidl文件生成的Java文件源代码就能发现有这么一段代码:

java代码:

1./**Local-sideIPCimplementationstubclass.*/

2.publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.demo.IMyService

复制代码

      原来Stub类就是继承于Binder类,也就是说RemoteService类和普通的Service类没什么不同,只是所返回的IBinder对象比较特别,是一个实现了AIDL接口的Binder。

      接下来就是关于所传递的数据Bean——Person类,是一个序列化的类,这里使用Parcelable接口来序列化,是Android提供的一个比Serializable效率更高的序列化类。

 

 Parcelable需要实现三个函数:

      1)voidwriteToParcel(Parceldest,intflags)将需要序列化存储的数据写入外部提供的Parcel对象dest。

读取Parcel数据的次序要和这里的write次序一致,否则可能会读错数据。

具体情况我没试验过!

      2)describeContents()没搞懂有什么用,反正直接返回0也可以

      3)staticfinalParcelable.Creator对象CREATOR  这个CREATOR命名是固定的,而它对应的接口有两个方法:

      createFromParcel(Parcelsource)实现从source创建出JavaBean实例的功能

      newArray(intsize)创建一个类型为T,长度为size的数组,仅一句话(returnnewT[size])即可。

估计本方法是供外部类反序列化本类数组使用。

  

    仔细观察Person类的代码和上面所说的内容:

java代码:

1.publicclassPersonimplementsParcelable{

2.

3.privateStringname;

4.privateStringtelNumber;

5.privateintage;

6.

7.publicPerson(){}

8.

9.publicPerson(Parcelpl){

10.name=pl.readString();

11.telNumber=pl.readString();

12.age=pl.readInt();

13.}

14.

15.publicStringgetName(){

16.returnname;

17.}

18.

19.publicvoidsetName(Stringname){

20.this.name=name;

21.}

22.

23.publicStringgetTelNumber(){

24.returntelNumber;

25.}

26.

27.publicvoidsetTelNumber(StringtelNumber){

28.this.telNumber=telNumber;

29.}

30.

31.publicintgetAge(){

32.returnage;

33.}

34.

35.publicvoidsetAge(intage){

36.this.age=age;

37.}

38.

39.@Override

40.publicintdescribeContents(){

41.return0;

42.}

43.

44.@Override

45.publicvoidwriteToParcel(Parceldest,intflags){

46.dest.writeString(name);

47.dest.writeString(telNumber);

48.dest.writeInt(age);

49.}

50.

51.publicstaticfinalParcelable.CreatorCREATOR=newParcelable.Creator(){

52.

53.@Override

54.publicPersoncreateFromParcel(Parcelsource){

55.returnnewPerson(source);

56.}

57.

58.@Override

59.publicPerson[]newArray(intsize){

60.returnnewPerson[size];

61.}

62.

63.};

64.}

复制代码

      然后创建Person.aidl文件,注意这里的parcelable和原来实现的Parcelable接口,开头的字母p一个小写一个大写:

java代码:

1.packageeoe.demo;

2.parcelablePerson;

复制代码

      对于实现AIDL接口,官方还提醒我们:

      1.调用者是不能保证在主线程执行的,所以从一调用的开始就需要考虑多线程处理,以及确保线程安全;

      2.IPC调用是同步的。

如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。

也就是IPC调用会挂起应用程序导致界面失去响应,这种情况应该考虑单独开启一个线程来处理。

  3.抛出的异常是不能返回给调用者(跨进程抛异常处理是不可取的)。

    3.客户端获取接口

    客户端如何获取AIDL接口呢?

通过IMyService.Stub.asInterface(service)来得到IMyService对象:

java代码:

1.privateIMyServicemRemoteService;

2.

3.privateServiceConnectionmRemoteConnection=newServiceConnection(){

4.publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){

5.mRemoteService=IMyService.Stub.asInterface(service);

6.}

7.

8.publicvoidonServiceDisconnected(ComponentNameclassName){

9.mRemoteService=null;

10.}

11.};

复制代码

 在生成的IMyService.java里面会找到这样的代码:

java代码:

1./**

2.*CastanIBinderobjectintoancom.demo.IMyServiceinterface,

3.*generatingaproxyifneeded.

4.*/

5.publicstaticcom.demo.IMyServiceasInterface(android.os.IBinderobj){...}

复制代码

    而service的绑定没有什么不同:

java代码:

1.if(mIsRemoteBound){

2.unbindService(mRemoteConnection);

3.}else{

4.bindService(newIntent("com.demo.IMyService"),

5.mRemoteConnection,Context.BIND_AUTO_CREATE);

6.}

7.

8.mIsRemoteBound=!

mIsRemoteBound;

复制代码

    通过IPC调用/传递数据

    客户端绑定service后就能通过IPC来调用/传递数据了,直接调用service对象的接口方法:

java代码:

1.addPersonButton.setOnClickListener(

2.newView.OnClickListener(){

3.privateintindex=0;

4.

5.@Override

6.publicvoidonClick(Viewview){

7.Personperson=newPerson();

8.index=index+1;

9.person.setName("Person"+index);

10.person.setAge(20);

11.person.setTelNumber("123456");

12.try{

13.mRemoteService.savePersonInfo(person);

14.}catch(RemoteExceptione){

15.e.printStackTrace();

16.}

17.}

18.});

19.

20.listPersonButton.setOnClickListener(

21.newView.OnClickListener(){

22.

23.@Override

24.publicvoidonClick(Viewview){

25.Listlist=null;

26.

27.try{

28.list=mRemoteService.getAllPerson();

29.}catch(RemoteExceptione){

30.e.printStackTrace();

31.}

32.

33.if(list!

=null){

34.StringBuildertext=newStringBuilder();

35.

36.for(Personperson:

list){

37.text.append("\nPersonname:

");

38.text.append(person.getName());

39.text.append("\nage:

");

40.text.append(person.getAge());

41.text.append("\ntelnumber:

");

42.text.append(person.getTelNumber());

43.}

44.

45.inputPersonEdit.setText(text);

46.}else{

47.Toast.makeText(ServiceActivity.this,"getdataerror",

48.Toast.LENGTH_SHORT).show();

49.}

50.}

51.});

复制代码

      Permission权限

      如果Service在AndroidManifest.xml中声明了全局的强制的访问权限,其他引用必须声明权限才能来start,stop或bind这个service.

      另外,service可以通过权限来保护她的IPC方法调用,通过调用checkCallingPermission(String)方法来确保可以执行这个操作。

      AndroidManifest.xml的Service元素

java代码:

1.

name=".RemoteService"android:

process=":

remote">

2.

3.

name="com.demo.IMyService"/>

4.

5.

复制代码

    这里的android:

process=":

remote",一开始我没有添加的,在同一个程序里使用IPC,即同一个程序作为客户端/服务器端,结果运行mRemoteService=IMyService.Stub.asInterface(service);时提示空指针异常。

java代码:

1.android:

process

2.Thenameoftheprocesswheretheserviceistorun.Normally,allcomponentsofanapplicationruninthedefaultprocesscreatedfortheapplication.Ithasthesamenameastheapplicationpackage.Theelement'sprocessattributecansetadifferentdefaultforallcomponents.Butcomponentcanoverridethedefaultwithitsownprocessattribute,allowingyoutospreadyourapplicationacrossmultip

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1