Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現進程間通信aidl的使用

Android實現進程間通信aidl的使用

編輯:關於Android編程

現在總結一下這個用法:
其實很簡單,主要就是以下的幾個步驟:
1.第一步,定義aidl文件(可以參照IWifiManager.java的定義來實現,其實就是定義一個Interface,提供被調用的方法);
例如 (IMyService.aidl):
package com.demo;

import com.demo.Person;

interface IMyService {
        void savePersonInfo(in Person person);//注意,這裡的Person類不是基本數據類型哦,要進行處理的,見下文
        List<Person> getAllPerson();
}


2.第二步,寫一個service,實現stub類(也就是實現剛才的那些接口),return stub類的對象(也就是binder);
    創建一個類實現剛才那個aidl的接口:
public class RemoteService extends Service {

        private LinkedList<Person> personList = new LinkedList<Person>();
        
        @Override
        public IBinder onBind(Intent intent) { //activity
                return mBinder;
        }

        private final IMyService.Stub mBinder = new IMyService.Stub(){

                @Override
                public void savePersonInfo(Person person) throws RemoteException {
                        if (person != null){
                                personList.add(person);
                        }
                }

                @Override
                public List<Person> getAllPerson() throws RemoteException {
                        return personList;
                }
        };
}


注:
  這裡會看到有一個名為IMyService.Stub類,查看aidl文件生成的Java文件源代碼就能發現有這麼一段代碼:
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.demo.IMyService
 原來Stub類就是繼承於Binder類,也就是說RemoteService類和普通的Service類沒什麼不同,只是所返回的IBinder對象比較特別,是一個實現了AIDL接口的Binder。

 


3.第三步,在activity裡面啟動service。
通過IMyService.Stub.asInterface(service)來得到IMyService對象:
private IMyService mRemoteService;

private ServiceConnection mRemoteConnection = new ServiceConnection() {   
        public void onServiceConnected(ComponentName className, IBinder service) {   
                mRemoteService = IMyService.Stub.asInterface(service);   
        }   

        public void onServiceDisconnected(ComponentName className) {   
                mRemoteService = null;   
        }   
};
注:
 在生成的IMyService.java裡面會找到這樣的代碼:
/**
* Cast an IBinder object into an com.demo.IMyService interface,
* generating a proxy if needed.
*/
public static com.demo.IMyService asInterface(android.os.IBinder obj) {...}

 


而service的綁定沒有什麼不同:
if (mIsRemoteBound) {
        unbindService(mRemoteConnection);
}else{
        bindService(new Intent("com.demo.IMyService"),
                               mRemoteConnection, Context.BIND_AUTO_CREATE);
}

mIsRemoteBound = !mIsRemoteBound;
 
通過IPC調用/傳遞數據
    客戶端綁定service後就能通過IPC來調用/傳遞數據了,直接調用service對象的接口方法:

addPersonButton.setOnClickListener(
                new View.OnClickListener(){
                        private int index = 0;

                        @Override
                        public void onClick(View view) {
                                Person person = new Person();
                                index = index + 1;
                                person.setName("Person" + index);
                                person.setAge(20);
                                person.setTelNumber("123456");
                                try {
                                        mRemoteService.savePersonInfo(person);
                                } catch (RemoteException e) {
                                        e.printStackTrace();
                                }
                        }
                });

listPersonButton.setOnClickListener(
                new View.OnClickListener(){

                        @Override
                        public void onClick(View view) {
                                List<Person> list = null;

                                try {
                                        list = mRemoteService.getAllPerson();
                                } catch (RemoteException e) {
                                        e.printStackTrace();
                                }

                                if (list != null){
                                        StringBuilder text = new StringBuilder();

                                        for(Person person : list){
                                                text.append("\nPerson name:");
                                                text.append(person.getName());
                                                text.append("\n             age :");
                                                text.append(person.getAge());
                                                text.append("\n tel number:");
                                                text.append(person.getTelNumber());
                                        }

                                        inputPersonEdit.setText(text);
                                }else {
                                        Toast.makeText(ServiceActivity.this, "get data error",
                                                        Toast.LENGTH_SHORT).show();
                                }
                        }
                });

 

 


另外關於第一步,附加的說一下。當aidl中的接口中的返回值或參數不是基本數據類型時,需要做如下的兩步:
1.給一個aidle的實現:
package com.demo;

parcelable Person;
 2.給一個序列化(實現java類)
public class Person implements Parcelable {

        private String name;
        private String telNumber;
        private int age;

        public Person() {}

        public Person(Parcel pl){
                name = pl.readString();
                telNumber = pl.readString();
                age = pl.readInt();
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }

        public String getTelNumber() {
                return telNumber;
        }

        public void setTelNumber(String telNumber) {
                this.telNumber = telNumber;
        }

        public int getAge() {
                return age;
        }

        public void setAge(int age) {
                this.age = age;
        }

        @Override
        public int describeContents() {
                return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(name);
                dest.writeString(telNumber);
                dest.writeInt(age);
        }

        public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {

                @Override
                public Person createFromParcel(Parcel source) {
                        return new Person(source);
                }

                @Override
                public Person[] newArray(int size) {
                        return new Person[size];
                }

        };
}


Parcelable需要實現三個函數:
    1) void writeToParcel(Parcel dest, int flags) 將需要序列化存儲的數據寫入外部提供的Parcel對象dest。而看了網上的代碼例子,個人猜測,讀取Parcel數據的次序要和這裡的write次序一致,否則可能會讀錯數據。具體情況我沒試驗過!
    2) describeContents() 沒搞懂有什麼用,反正直接返回0也可以
    3) static final Parcelable.Creator對象CREATOR  這個CREATOR命名是固定的,而它對應的接口有兩個方法:
    createFromParcel(Parcel source) 實現從source創建出JavaBean實例的功能
    newArray(int size) 創建一個類型為T,長度為size的數組,僅一句話(return new T[size])即可。估計本方法是供外部類反序列化本類數組使用。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved