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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android AIDL使用介绍(2)自定义数据类型的传递

發布時間:2024/9/21 Android 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android AIDL使用介绍(2)自定义数据类型的传递 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.背景

默認情況下,AIDL只支持下列數據類型:

  • Java八種基礎數據類型(如 int、long、char、boolean 等);
  • String字符串;
  • CharSequence字符序列;
  • List列表,List中的所有元素須是前面提到的數據類型,或者是Parcelable類型(這也是本文準備講解的);
  • Map,Map 中的所有元素必須是以上列表中支持的數據類型,或者您所聲明的由 AIDL 生成的其他接口或Parcelable 類型;

如果想在進程間傳遞以上數據類型之外的對象該怎么辦?這就需用到Parcelable接口,Parcelable意思是“可包裹的”,是Android系統可用的序列化接口的一種,另外一種是來自java的Serialable,和Parcelable相比,Serialable的使用較為簡單,如果只是保存數據到本地這類應用,使用Serialable即可,但在進程間通訊,則建議使用Parcelable。

2.序列化和反序列化

Parcelable是序列化接口,那么什么是序列化,為什么進程間傳輸自定義對象需要使用序列化?百度百科對序列化的定義如下:

序列化是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程。在序列化期間,對象將其當前狀態寫入到臨時或持久性存儲區。之后,可以通過從存儲區中讀取或反序列化對象的狀態,重新創建該對象。

數據在內存中是字節形態,數據分解到最后都是0和1字節流,這就像萬物分解到最后都是原子一樣,進程A要傳遞數據給進程B,同樣是以字節形式傳遞,對于基本數據類型,例如進程A傳遞int類型數據給進程B,因為進程A和進程B都知道int類型,因此進程B可以直接從內存中還原出數據,而對于自定義數據類型,例如進程A自定義了一個Student對象,進程B并不知道,如果直接傳遞字節流給進程B,面對一堆字節流,進程B不知道怎么重構還原,需要進程A告訴重構方法,這便是序列化和反序列化的過程,這也是傳遞自定義對象需使用序列化的原因。

3.使用示例

  • 服務端創建自定義類型,這包括創建Student.java和Student.aidl,兩個文件分別在aidl目錄下和java目錄下,但兩個文件所在的包名必須相同,否則編譯不通。

    java代碼里實現Parcelable里的接口,其中值得注意的是writeToParcel方法和readFromParcel方法里面的寫和讀取順序是需要一一對應的,Parcel意為包裹,writeToParcel是快遞打包,作用是獲取對象的當前狀態并將其寫入 Parcel,readFromParcel是拆快遞,打包和拆的順序應一一對應,否則讀取數據會混亂,例如writeToParcel寫數據的順序如下:
  • public void writeToParcel(Parcel dest, int flags) {dest.writeInt(id);//寫一個int類型的值dest.writeString(name);//寫一個String類型的值dest.writeString(gender);//寫一個String類型的值dest.writeInt(age);//寫一個int類型的值}

    則對應的readFromParcel應按照相應的順序讀取

    public void readFromParcel(Parcel source) {id = source.readInt();name = source.readString();gender = source.readString();age = source.readInt();}

    另外,自定義類型中必須含有一個名稱為CREATOR的靜態成員,該成員是實現 Parcelable.Creator 接口的對象,用于從Parcel生成Parcelable的實例。

    public static final Creator<Student> CREATOR = new Creator<Student>() {@Overridepublic Student createFromParcel(Parcel in) {return new Student(in);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};

    完整的自定義類型java代碼如下:

    package com.pm.service; import android.os.Parcel; import android.os.Parcelable;public class Student implements Parcelable {private int id;private String name;private String gender;private int age;protected Student(Parcel in) {id = in.readInt();name = in.readString();gender = in.readString();age = in.readInt();}public Student(int id, String name, String gender, int age) {this.id = id;this.name = name;this.gender = gender;this.age = age;}public Student(){}public static final Creator<Student> CREATOR = new Creator<Student>() {@Overridepublic Student createFromParcel(Parcel in) {return new Student(in);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(id);dest.writeString(name);dest.writeString(gender);dest.writeInt(age);}public void readFromParcel(Parcel source) {id = source.readInt();name = source.readString();gender = source.readString();age = source.readInt();}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}

    java文件創建好了之后,則可以開始創建同名的Parcelable類的aidl文件,代碼如下,代碼較簡單,只是聲明Student是parcelable

    // Student.aidl package com.pm.service;// Declare any non-default types here with import statements import com.pm.service.Student;parcelable Student;
  • 自定義類型創建好了之后,便可以開始使用了,這跟使用基本類型一樣,不過,在使用之前,需要先使用import引入自定義類型,aidl代碼如下,該代碼是在上篇博客的基礎上新增接口,因此代碼其他部分不再做說明,具體請參考博客Android AIDL使用介紹(1)基本使用,
  • // ServiceAidlInterface.aidl package com.pm.service;// Declare any non-default types here with import statements import com.pm.service.Student;interface ServiceAidlInterface {String ServiceGreet();List<Student> getStudentList(); }

    aidl代碼編寫好了之后,記得同步一下工程,然后在Service里實現新增的方法,完整的代碼如下:

    package com.pm.service;import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException;import java.util.LinkedList; import java.util.List;public class MyService extends Service {private ServiceAidlInterface.Stub serviceAidlInterface= new ServiceAidlInterface.Stub() {@Overridepublic String ServiceGreet() throws RemoteException {return "Hello Client!";}@Overridepublic List<Student> getStudentList() throws RemoteException {List<Student> list = new LinkedList<>();for (int i = 0; i < 10; i++) {list.add(new Student(i,"s1"+i,"man",i+10));}return list;}};@Overridepublic IBinder onBind(Intent intent) {return serviceAidlInterface.asBinder();} }

    這樣一來,服務端要做的事都已完成,接下來是客戶端的內容。

  • 從服務端拷貝aidl目錄下的文件和Student.java文件到客戶端,存放的目錄見圖,需要注意的是,客戶端的Student的aidl文件和java文件也要在相同的包名下,因客戶端也是在上篇博客的demo的基礎上編寫,只需增加一個按鈕做事件點擊之用,把服務端傳遞過來的Student對象的實例打印出來,完整的代碼見下:
  • package com.pm.myaidldemo;import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView;import com.pm.service.ServiceAidlInterface; import com.pm.service.Student;import java.util.ArrayList; import java.util.List;public class MainActivity extends AppCompatActivity {String TAG="AIDLDemo";private Button bServiceGreet;private Button bGetStu;private TextView tvInfo;private ServiceAidlInterface serviceAidlInterface;private ServiceConnection connection=new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {serviceAidlInterface = ServiceAidlInterface.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindService();bServiceGreet=findViewById(R.id.btnServiceGreet);bGetStu=findViewById(R.id.btnGetStudent);tvInfo=findViewById(R.id.tvInfo);bServiceGreet.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String greet= null;try {greet = serviceAidlInterface.ServiceGreet();tvInfo.setText(greet);} catch (RemoteException e) {e.printStackTrace();}}});bGetStu.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {StringBuilder sb=new StringBuilder();List<Student> stulist= serviceAidlInterface.getStudentList();for(int i=0;i<stulist.size()-5;i++){sb.append("ID:"+stulist.get(i).getId()+"\n");sb.append("Name:"+stulist.get(i).getName()+"\n");sb.append("Gender:"+stulist.get(i).getGender()+"\n");sb.append("Age:"+stulist.get(i).getAge()+"\n");tvInfo.setText(sb.toString());}} catch (RemoteException e) {e.printStackTrace();}}});}private void bindService() {Intent intent = new Intent();intent.setAction("com.pm.service.MyService");intent.setPackage("com.pm.service");this.bindService(intent, connection, BIND_AUTO_CREATE);Log.e(TAG, "bindService: finish!");} }

    客戶端編寫好了之后,運行的效果如下:

    4.總結

    進程間傳遞自定義對象需要實現Parcelable接口,通過序列化和反序列化實現,相比java原生的Serialization各有特色,如果是數據存儲到磁盤上,建議使用java Serialization,如果是進程間通訊,則使用Parcelable。另外自定義類型的java和aidl文檔要在相同的包名下,否則會提示找不到類的錯誤,自定義類型創建好了之后,便可以像aidl基本數據類型一樣使用。

    總結

    以上是生活随笔為你收集整理的Android AIDL使用介绍(2)自定义数据类型的传递的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。