Android:Service之AIDL传递复杂对象

   AIDL传递复杂类型对象的特殊处理

  前面已经介绍了通过AIDL接口在进程间传递系统允许的数据,如果需要传递一个复杂类型的对象,就没那么简单了,需要额外做一些处理。如下:

  定义数据接口的AIDL文件中,使用parcelable关键字,例如:parcelable Message;

  在其数据实现类中实现Parcelable接口,并实现对应的方法。

  在业务接口的AIDL文件中,使用import引入数据接口AIDL的包名。

  例如:Message.aidl

  1 parcelable Message;

  例如:IGetMsg.aidl

  1 package com.example.aidlservicedemo.domain;

  2

  3 // 这是两个自定义类

  4 import com.example.aidlservicedemo.domain.Message;

  5 import com.example.aidlservicedemo.domain.User;

  6

  7 interface IGetMsg{

  8 // 在AIDL接口中定义一个getMes方法

  9 List getMes(in User us);

  10 }

  Parcelable与Parcel接口

  先来说说Android对象序列化,在Android中序列化对象主要有两种方式,实现Serializable接口或是实现Parcelable接口。Serializable接口是JavaSE原生支持的,而Parcelable接口是Android所特有的,它的序列化和反序列化的效率均比Serializable接口高,而AIDL进行在进程间通信(IPC),就是需要实现这个Parcelable接口。

  Parcelable接口的作用:实现了Parcelable接口的实例,可以将自身的数据信息写入一个Parcel对象,也可以从parcel中恢复到对象的状态。而Parcel就是完成数据序列化写入的载体。

  上面提到Parcel,再来聊聊Parcel是什么?Android系统设计之初,定位就是针对内存受限的设备,因此对性能要求更好,所以系统中采用进程间通信(IPC)机制,必然要求性能更优良的序列化方式,所以Parcel就被设计出来了,其定位就是轻量级的高效的对象序列化机制与反序列化机制。如果读一下Android的底层代码,会发现Parcel是使用C++实现的,底层直接通过Parcel指针操作内存实现,所以它的才更高效。

  Parcel也提供了一系列的方法帮助写入数据与读取数据,这里简单介绍一下:

  obtain():在池中获取一个新的Parcel。

  dataSize():得到当前Parcel对象的实际存储空间。

  dataPostion():获取当前Parcel对象的偏移量。

  setDataPosition():设置当前Parcel对象的偏移量。

  recyle():清空、回收当前Parcel对象的内存。

  writeXxx():向当前Parcel对象写入数据,具有多种重载。

  readXxx():从当前Parcel对象读取数据,具有多种重载。

  简单来说,Parcelable通过writeToParcel()方法,对复杂对象的数据写入Parcel的方式进行对象序列化,然后在需要的时候,通过其内定义的静态属性CREATOR.createFromParcel()进行反序列化的操作。Parcelable对Parcel进行了包装,其内部就是通过操作Parcel进行序列化与反序列化的。

  Parcelable与Parcel均定义在android.os包下,而这种机制不仅用于AIDL,还可以用于Intent传递数据等其他地方,这不是本篇博客的主题,以后用到再详细介绍。

  实现Parcelable接口

  定义好数据接口的AIDL文件后,需要定义一个数据实现类,实现Parcelable接口,并实现对应的方法,Parcelable有如下几个必须要实现的抽象方法:

  abstract int describeContents():返回一个位掩码,表示一组特殊对象类型的Parcelable,一般返回0即可。

  asbtract void writeToParcel(Parcel dest,int flags):实现对象的序列化,通过Parcel的一系列writeXxx()方法序列化对象。

  除了上面两个方法,还需要在实现类中定义一个名为"CREATOR",类型为"Parcelable.Creator"的泛型静态属性,它实现了对象的反序列化。它也有两个必须实现的抽象方法:

  abstract T createFromParcel(Parcel source):通过source对象,根据writeToParcel()方法序列化的数据,反序列化一个Parcelable对象。

  abstract T[] newArray(int size):创建一个新的Parcelable对象的数组。

  例如:

  1 @Override

  2 public int describeContents() {

  3 return 0;

  4 }

  5

  6 @Override

  7 public void writeToParcel(Parcel dest, int flags) {

  8 Log.i("main", "服务端Message被序列化");

  9 dest.writeInt(id);

  10 dest.writeString(msgText);

  11 dest.writeString(fromName);

  12 dest.writeString(date);

  13 }

  14

  15 public static final Parcelable.Creator CREATOR = new Creator() {

  16

  17 @Override

  18 public Message[] newArray(int size) {

  19 return new Message[size];

  20 }

  21

  22 @Override

  23 public Message createFromParcel(Parcel source) {

  24 Log.i("main", "服务端Message被反序列化");

  25 return new Message(source.readInt(), source.readString(),

  26 source.readString(), source.readString());

  27 }

  28 };

  从上面示例中可以看出,使用writeToParcel()方法进行序列化,通过CREATOR.createFromParcel进行反序列化,它们都传递一个Parcel类型的对象,这里要注意的是两个方法中Parcel对象的writeXxx()和readXxx()方法的顺序必须一致,因为一般序列化数据是以链的形式序列化的,如果顺序不对,反序列化的数据会出错。

  AIDL传递复杂类型对象Demo

  关键点已经讲到, 下面通过一个简单的Demo来演示AIDL传递复杂对象。

  AIDL接口:

  com.example.aidlservicedemo.domain.Message.aidl

  Message.aidl

  com.example.aidlservicedemo.domain.Message.java

  Message.java

  com.example.aidlservicedemo.domain.User.aidl

  User.aidl

  com.example.aidlservicedemo.domain.User.java

  User.java

  服务:

  com.example.aidlservicedemo.

  CustomTypeService.java

  客户端:

  com.example.aidlClientdemo.

  CustomTypeActivity.java

  效果展示:

 
  AIDL传递对象序列化过程详解

  通过上面Demo打印的日志,解释一下序列化的过程,打开Logcat查看日志。


  从上图的PID列可以看出这是两个线程间的交互。

  流程是这样的,客户端传递一个User对象给服务端,服务端通过User对象处理数据,返回两个Message对象给客户端。

  首先,在客户端传递给服务端User对象前,客户端先把User对象序列化,然后传递给服务端之后,服务端接收到的是一段序列化后的数据,它再按照原定的规则对数据进行反序列化,然后处理User。当服务端查到这个User有两条Message时,需要传递这两条Message对象给客户端,在传递前对Message对象进行序列化,客户端收到服务端传递过来的序列化后的数据,再根据既定的规则进行反序列化,得到正确的对象。

  从这个流程可以看出,在进程间传递的数据必定是被序列化过的,否则无法传递。而对于那些AIDL默认允许传递的数据类型(int、double、String、List等),它们其实内部已经实现了序列化,所以无需我们再去指定序列化规则。但是对于复杂类型对象而言,系统无法知道如何去序列化与反序列化,所以需要我们指定规则。

时间: 2024-09-23 17:32:56

Android:Service之AIDL传递复杂对象的相关文章

Android:Service之AIDL传递系统基本类型数据

  什么是AIDL? 先来回顾一下,Android在本地的Service中如何与其它组件进行交互的,首先Service必须实现其onBind()方法,然后在onBind方法传递一个IBinder接口的实现,而在其它组件中使用bindService()绑定一个服务,再通过其中的参数ServiceConnection对象获取到Service中定义的IBinder接口的实现.那么与Service进行数据交互,其实就是传递一个IBinder,通过这个IBinder进行交互. 而现在就碰到一个问题,在同一

Android service binder aidl 关系

/********************************************************************************** * Android service binder aidl 关系 * 声明: * 最近一直被Android中的service.binder.aidl这三者之间的关系给搞得有点难受, * 于是就自己花了点时间,将他们之间的关系给画出来,这样思维上就清晰多了,也方便 * 和朋友沟通,减少沟通成本. * * 2016-1-10 晴 深圳

Android Service生命周期及用法

上一节我讲解了Android Activity的生命周期,这一节我将讲解一下Service,首先我们要知道Service具体是干什么的,什么时候用到?以及它的生命周期等. Service概念及用途: Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行,那我们什么时候会用到Service呢?比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当我们退出播放音乐的应用,如果不

我的Android进阶之旅------>Android Service学习之AIDL, Parcelable和远程服务

AIDL的作用     由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象.在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界.     通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作.       AIDL (Android Interface Definition Language) 是一种I

Android Service学习之AIDL, Parcelable和远程服务

AIDL的作用 由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象.在Android平台,一 个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界. 通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作. AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在

《Android开发进阶:从小工到专家》——第1章,第1.2节Service与AIDL

1.2 Service与AIDLService是Android中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务.但不要被"后台"二字所迷惑,Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作. Service的运行不依赖于任何用户界面,即使程序被切换到后台或者用户打开了另外一个应用程序,Service仍然

我的Android进阶之旅------>Android Service学习之AIDL, Parcelable和远程服务实例

通过上一篇(Android Service学习之AIDL, Parcelable和远程服务)的介绍,这一篇写一个小实例来实践一下 step1:建立两个应用,分别为RemoteService和RemoteServiceClient                                         先编写服务器端的内容 step2:开始编写一个StudentQuery.aidl文件      AIDL(Android Interface Definition Language),用来定

对象-Android service与Activity的新手问题

问题描述 Android service与Activity的新手问题 一个音乐播放器,要在service里面进行音乐播放,有MediaPlayer,Handler,List, Runnable几个对象,想从Activity里面传进去,用什么办法可以啊??实现Parcelable接口行吗? 解决方案 Android service向activity发送信息 解决方案二: 传这么多消息干嘛,感觉传个音乐路径以及状态值就可以了 解决方案三: bindService(),对于activity与servi

Android开发中Intent传递对象的方法分析_Android

本文实例分析了Android开发中Intent传递对象的方法.分享给大家供大家参考,具体如下: 方法一: 利用方法:public Intent putExtra (String name, Parcelable value)传递一个Parceable的参数,此方法的参数被序列化到内存. 利用方法:public Intent putExtra (String name, Serializable value)传递一个实现了序列化接口类的对象,此方法的实参被序列化到磁盘. 方法二: 把数据存放到应用