日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

android--service之aidl传递复杂对象,Android--Service之AIDL传递复杂对象

發(fā)布時(shí)間:2025/3/15 Android 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android--service之aidl传递复杂对象,Android--Service之AIDL传递复杂对象 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

Android的AIDL不僅可以在綁定服務(wù)中傳遞一些Android規(guī)定的數(shù)據(jù)類型的數(shù)據(jù),還可以傳遞一些復(fù)雜類型的數(shù)據(jù)。但是與傳遞系統(tǒng)允許的數(shù)據(jù)類型相比,復(fù)雜類型數(shù)據(jù)的傳遞要做更多的工作,本篇博客就講解一下如何使用AIDL接口通過綁定服務(wù)在進(jìn)程間傳遞數(shù)據(jù)。關(guān)于AIDL傳遞規(guī)定類型數(shù)據(jù)的內(nèi)容,不了解的朋友可以看看之前的博客:AIDL傳遞系統(tǒng)允許類型數(shù)據(jù)。

本篇博客的主要內(nèi)容:

AIDL傳遞復(fù)雜類型對(duì)象的特殊處理

前面已經(jīng)介紹了通過AIDL接口在進(jìn)程間傳遞系統(tǒng)允許的數(shù)據(jù),如果需要傳遞一個(gè)復(fù)雜類型的對(duì)象,就沒那么簡(jiǎn)單了,需要額外做一些處理。如下:

定義數(shù)據(jù)接口的AIDL文件中,使用parcelable關(guān)鍵字,例如:parcelable Message;

在其數(shù)據(jù)實(shí)現(xiàn)類中實(shí)現(xiàn)Parcelable接口,并實(shí)現(xiàn)對(duì)應(yīng)的方法。

在業(yè)務(wù)接口的AIDL文件中,使用import引入數(shù)據(jù)接口AIDL的包名。

例如:Message.aidl

1 parcelable Message;

例如:IGetMsg.aidl

1 package com.example.aidlservicedemo.domain;

2

3 // 這是兩個(gè)自定義類

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

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

6

7 interface IGetMsg{

8 // 在AIDL接口中定義一個(gè)getMes方法

9 List getMes(in User us);

10 }

Parcelable與Parcel接口

先來說說Android對(duì)象序列化,在Android中序列化對(duì)象主要有兩種方式,實(shí)現(xiàn)Serializable接口或是實(shí)現(xiàn)Parcelable接口。Serializable接口是JavaSE原生支持的,而Parcelable接口是Android所特有的,它的序列化和反序列化的效率均比Serializable接口高,而AIDL進(jìn)行在進(jìn)程間通信(IPC),就是需要實(shí)現(xiàn)這個(gè)Parcelable接口。

Parcelable接口的作用:實(shí)現(xiàn)了Parcelable接口的實(shí)例,可以將自身的數(shù)據(jù)信息寫入一個(gè)Parcel對(duì)象,也可以從parcel中恢復(fù)到對(duì)象的狀態(tài)。而Parcel就是完成數(shù)據(jù)序列化寫入的載體。

上面提到Parcel,再來聊聊Parcel是什么?Android系統(tǒng)設(shè)計(jì)之初,定位就是針對(duì)內(nèi)存受限的設(shè)備,因此對(duì)性能要求更好,所以系統(tǒng)中采用進(jìn)程間通信(IPC)機(jī)制,必然要求性能更優(yōu)良的序列化方式,所以Parcel就被設(shè)計(jì)出來了,其定位就是輕量級(jí)的高效的對(duì)象序列化機(jī)制與反序列化機(jī)制。如果讀一下Android的底層代碼,會(huì)發(fā)現(xiàn)Parcel是使用C++實(shí)現(xiàn)的,底層直接通過Parcel指針操作內(nèi)存實(shí)現(xiàn),所以它的才更高效。

Parcel也提供了一系列的方法幫助寫入數(shù)據(jù)與讀取數(shù)據(jù),這里簡(jiǎn)單介紹一下:

obtain():在池中獲取一個(gè)新的Parcel。

dataSize():得到當(dāng)前Parcel對(duì)象的實(shí)際存儲(chǔ)空間。

dataPostion():獲取當(dāng)前Parcel對(duì)象的偏移量。

setDataPosition():設(shè)置當(dāng)前Parcel對(duì)象的偏移量。

recyle():清空、回收當(dāng)前Parcel對(duì)象的內(nèi)存。

writeXxx():向當(dāng)前Parcel對(duì)象寫入數(shù)據(jù),具有多種重載。

readXxx():從當(dāng)前Parcel對(duì)象讀取數(shù)據(jù),具有多種重載。

簡(jiǎn)單來說,Parcelable通過writeToParcel()方法,對(duì)復(fù)雜對(duì)象的數(shù)據(jù)寫入Parcel的方式進(jìn)行對(duì)象序列化,然后在需要的時(shí)候,通過其內(nèi)定義的靜態(tài)屬性CREATOR.createFromParcel()進(jìn)行反序列化的操作。Parcelable對(duì)Parcel進(jìn)行了包裝,其內(nèi)部就是通過操作Parcel進(jìn)行序列化與反序列化的。

Parcelable與Parcel均定義在android.os包下,而這種機(jī)制不僅用于AIDL,還可以用于Intent傳遞數(shù)據(jù)等其他地方,這不是本篇博客的主題,以后用到再詳細(xì)介紹。

實(shí)現(xiàn)Parcelable接口

定義好數(shù)據(jù)接口的AIDL文件后,需要定義一個(gè)數(shù)據(jù)實(shí)現(xiàn)類,實(shí)現(xiàn)Parcelable接口,并實(shí)現(xiàn)對(duì)應(yīng)的方法,Parcelable有如下幾個(gè)必須要實(shí)現(xiàn)的抽象方法:

abstract int describeContents():返回一個(gè)位掩碼,表示一組特殊對(duì)象類型的Parcelable,一般返回0即可。

asbtract void writeToParcel(Parcel dest,int flags):實(shí)現(xiàn)對(duì)象的序列化,通過Parcel的一系列writeXxx()方法序列化對(duì)象。

除了上面兩個(gè)方法,還需要在實(shí)現(xiàn)類中定義一個(gè)名為"CREATOR",類型為"Parcelable.Creator"的泛型靜態(tài)屬性,它實(shí)現(xiàn)了對(duì)象的反序列化。它也有兩個(gè)必須實(shí)現(xiàn)的抽象方法:

abstract T createFromParcel(Parcel source):通過source對(duì)象,根據(jù)writeToParcel()方法序列化的數(shù)據(jù),反序列化一個(gè)Parcelable對(duì)象。

abstract T[] newArray(int size):創(chuàng)建一個(gè)新的Parcelable對(duì)象的數(shù)組。

例如:

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", "服務(wù)端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", "服務(wù)端Message被反序列化");

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

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

27 }

28 };

從上面示例中可以看出,使用writeToParcel()方法進(jìn)行序列化,通過CREATOR.createFromParcel進(jìn)行反序列化,它們都傳遞一個(gè)Parcel類型的對(duì)象,這里要注意的是兩個(gè)方法中Parcel對(duì)象的writeXxx()和readXxx()方法的順序必須一致,因?yàn)橐话阈蛄谢瘮?shù)據(jù)是以鏈的形式序列化的,如果順序不對(duì),反序列化的數(shù)據(jù)會(huì)出錯(cuò)。

AIDL傳遞復(fù)雜類型對(duì)象Demo

關(guān)鍵點(diǎn)已經(jīng)講到, 下面通過一個(gè)簡(jiǎn)單的Demo來演示AIDL傳遞復(fù)雜對(duì)象。

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

服務(wù):

com.example.aidlservicedemo.

?CustomTypeService.java

客戶端:

com.example.aidlClientdemo.

?CustomTypeActivity.java

效果展示:

AIDL傳遞對(duì)象序列化過程詳解

通過上面Demo打印的日志,解釋一下序列化的過程,打開Logcat查看日志。

從上圖的PID列可以看出這是兩個(gè)線程間的交互。

流程是這樣的,客戶端傳遞一個(gè)User對(duì)象給服務(wù)端,服務(wù)端通過User對(duì)象處理數(shù)據(jù),返回兩個(gè)Message對(duì)象給客戶端。

首先,在客戶端傳遞給服務(wù)端User對(duì)象前,客戶端先把User對(duì)象序列化,然后傳遞給服務(wù)端之后,服務(wù)端接收到的是一段序列化后的數(shù)據(jù),它再按照原定的規(guī)則對(duì)數(shù)據(jù)進(jìn)行反序列化,然后處理User。當(dāng)服務(wù)端查到這個(gè)User有兩條Message時(shí),需要傳遞這兩條Message對(duì)象給客戶端,在傳遞前對(duì)Message對(duì)象進(jìn)行序列化,客戶端收到服務(wù)端傳遞過來的序列化后的數(shù)據(jù),再根據(jù)既定的規(guī)則進(jìn)行反序列化,得到正確的對(duì)象。

從這個(gè)流程可以看出,在進(jìn)程間傳遞的數(shù)據(jù)必定是被序列化過的,否則無法傳遞。而對(duì)于那些AIDL默認(rèn)允許傳遞的數(shù)據(jù)類型(int、double、String、List等),它們其實(shí)內(nèi)部已經(jīng)實(shí)現(xiàn)了序列化,所以無需我們?cè)偃ブ付ㄐ蛄谢?guī)則。但是對(duì)于復(fù)雜類型對(duì)象而言,系統(tǒng)無法知道如何去序列化與反序列化,所以需要我們指定規(guī)則。

總結(jié)

以上是生活随笔為你收集整理的android--service之aidl传递复杂对象,Android--Service之AIDL传递复杂对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。