一个后台服务,提供一个接口,想要利用上层的应用传递下来的数据,进行处理。但是这类数据种类繁多,该怎么办呢?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这些,那么我们可以再抽出一个父类。继承关系如下: