1. 程式人生 > >Android如何通過parcelable實現跨程序之間多型的型別的傳遞。

Android如何通過parcelable實現跨程序之間多型的型別的傳遞。

一個後臺服務,提供一個介面,想要利用上層的應用傳遞下來的資料,進行處理。但是這類資料種類繁多,該怎麼辦呢?Android 提供的parcelable將這些資料傳遞給世界的另一邊。之前看了網路上的做法,有一篇文章無限接近實現了,但是由於部分錯誤,導致了我一直是失敗的,後來自己經過摸索才終於找到原因。廢話不多說,講講乾貨。

假設我們在服務端有多個數據Bean,如ABean, BBean,CBean等待傳輸,那麼就讓他們愉快的去繼承一個RootBean的抽象類,記住這裡的父類一定要是抽象類,否則後面會讓你生不如死。多型的核心就是這個抽象類(這裡千萬不要去實現Creator交給他的兒子吧)

import android.os.Parcel;
import android.os.Parcelable;

public abstract class RootBean implements Parcelable {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }

    protected RootData(Parcel in) {
    }

    protected RootData() {

    }

}

看看ABean是怎麼繼承它爸爸的

import android.os.Parcel;

public class ABean extends RootBean {
    int childData;

    public int getChildData() {
        return childData;
    }

    public void setChildData(int childData) {
        this.childData = childData;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeInt(this.childData);
    }

    public ChildData() {
        super();
    }

    protected ChildData(Parcel in) {
        super(in);
        this.childData = in.readInt();

    }

    public static final Creator<ChildData> CREATOR = new Creator<ChildData>() {
        public ChildData createFromParcel(Parcel in) {
            return new ChildData(in);
        }

        public ChildData[] newArray(int size) {
            return new ChildData[size];
        }
    };
}

很簡單,沒有什麼難度,按照通用的parcelable的自動生成方式就可以了。

伺服器端提供了一個,且有且僅有一個介面傳遞資料,這個介面的引數只能有一個,按照上面的設計思路,這裡我們想傳一個父類(RootBean)到世界的盡頭,在世界的盡頭根據"多型"再來動態生成相應的兒子物件。

為了實現上面的想法,我們這裡需要一個Wrapper類來包裝下自己,以便於自己能夠被傳輸出去。

public class DataWrapper implements Parcelable {

    private RootBea rootBean;

    public RootData getRootBean() {
        return rootBean;
    }

    public void setRootBean(RootData rootBean) {
        this.rootBean= rootDean;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeParcelable(this.rootData, flags);
    }

    public DataWrapper() {
    }

    protected DataWrapper(Parcel in) {
        this.rootBean = in.readParcelable(RootData.class.getClassLoader());//關鍵
    }

    public static final Creator<DataWrapper> CREATOR = new Creator<DataWrapper>() {
        @Override
        public DataWrapper createFromParcel(Parcel source) {
            return new DataWrapper(source);
        }

        @Override
        public DataWrapper[] newArray(int size) {
            return new DataWrapper[size];
        }
    };
}
這裡的關鍵就是
 this.rootBean = in.readParcelable(RootBean.class.getClassLoader());

這個是parcelable獲取物件的類,如果沒有這句什麼也白搭,如果父類不是抽象,這裡也沒用。

有人會問,如果這個資料到了上面,我怎麼判斷到底是啥型別的資料,這裡可以在這個Wrapper類裡面加個屬性比如type或者啥的,具體怎麼寫就不在這裡描述了,很簡單,和普通的parcelable加一個屬性一樣。

下面講講怎麼傳送這個資料吧。

由於需要傳遞一個物件型別的資料而非通用型別的資料,這裡需要宣告一個和DataWrapper.java類同名的一個物件AIDL檔案

// IDataWrapper.aidl
package com.hxcode.polymorphism;

// Declare any non-default types here with import statements

parcelable DataWrapper;

注意包名和DataWrapper.java要一致,注意包名要一致,注意包名要一致,重要的事情說三遍。

下面就是後臺服務定義的一個討要資料的介面了(我不是要飯的)

package com.hxcode.polymorphism;

// Declare any non-default types here with import statements
import com.hxcode.polymorphism.DataWrapper;

interface IRemoteService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void getData(in DataWrapper data);
}
這個介面定義了,那就需要實現他
public class ServiceImpl extends IRemoteService.Stub {

    private final static String TAG = "ServiceImpl";

    @Override
    public void sendData(DataWrapper dataWrapper) throws RemoteException {
        ABean childData = (ABean) dataWrapper.getRootBean();
        int data = childData.getChildData();//get child data
        Log.d(TAG, "send data is:"+data);
    }
}

如何呼叫定義的這個AIDL定義的介面?

這裡不再寫如何實現的,無非就是先繫結service,然後再獲取IBinder等等標準的做法。

這裡需要提到一點的是,有的時候,有些資料型別的有些屬性是一致的,假設ABean, BBean, CBean都有名稱name和地址address這些,那麼我們可以再抽出一個父類。繼承關係如下: