在 Activity 跟 Service 的通信过程中,一般用来传递数据的载体就是Intent了,一般用来传数据呢,我们都是通过putExtra 函数来传递简单的String,int, long类型的值,
但是现在存在这样一个问题:
1)在Activity里面有一个歌曲列表 List, 里面的对象是自定义的一个MusicInfo类,即 List<MusicInfo> 对象,这是用来展现的。
2)在后台Service中,也需要这样一个List<MusicInfo>, 来实现当歌曲播放结束的时候,自动循环播放或者顺序播放,或者随机播放。
我想要把整个List<MusicInfo> 给传过去,那该怎么办?
一般来说,将自定义的对象放到 Intent 里面来传递,可以有两种实现方法:
1)传递的对象实现 Serializable 接口,代码如下:
class MusicInfo implements Serializable{
private static final long serialVersionUID = -39201440269615431L;
...
}
在设置 Intent 的时候,
intent.putExtra("music", new MusicInfo());
在Service 端接收 Intent 的时候,
intent.getSerializableExtra("music");
2)传递的对象实现Parcelable 接口,代码如下:
static class MusicInfo implements Parcelable{
private static final long serialVersionUID = -39201440269615431L;
...
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(title);
dest.writeString(album);
dest.writeString(artist);
dest.writeString(url);
dest.writeLong(duration);
dest.writeLong(size);
}
public static final Parcelable.Creator<MusicInfo> CREATOR = new Creator<MusicLoader.MusicInfo>() {
@Override
public MusicInfo[] newArray(int size) {
// TODO Auto-generated method stub
return new MusicInfo[size];
}
@Override
public MusicInfo createFromParcel(Parcel source) {
// TODO Auto-generated method stub
MusicInfo musicInfo = new MusicInfo();
musicInfo.setId(source.readLong());
musicInfo.setTitle(source.readString());
musicInfo.setAlbum(source.readString());
musicInfo.setArtist(source.readString());
musicInfo.setUrl(source.readString());
musicInfo.setDuration(source.readLong());
musicInfo.setSize(source.readLong());
return musicInfo;
}
};
其中下面三个方法是实现Parcelable 接口必须实现的:
1)describeContent () : 请参考:http://stackoverflow.com/questions/4076946/parcelable-where-when-is-describecontents-used
2)writeToParcel :将 MusicInfo 类中的值写放到一个Parcel容器中,这就是用来传递值的了
3)public static final Parcelable.Creator<T> CREATOR = new Creator<T>() :这是一个静态的接口,而且其名字一定要是CREATOR (=_=!!), 里面提供了两个方法,
3.1)public T[] newArray(int size) {} :返回一个 T 类型的数组
3.2)public T createFromParcel(Parcel source) {} : 从Parcel 中获取之前写入的数据,并封装成Parcel
对于这个Creator的接口,我的理解是,当我们把数据包装到Parcel中之后,它会被包装成一个 T 类型的数组(Music[] parcel),然后传递给Service或者其它Activity的时候,当系统要将Parcel中数据重新解析成我们自定义的对象的时候,它需要去调用Creator这个接口,先根据传入对象的长度 new 出一个T数组, 然后再CreateFromParcel,将内容转化成一个一个的 T 类型对象,放到数组中,返回给接收者。
可能也正是因为封装数组这种特性,当我们要在Android中传递开篇中提到的 List<MusicInfo> 集合的时候,只能实现Parcelable接口,用Serializable 是实现不了的。
另外有一点要注意的是,我们从Parcel 解析自定义的对象的时候,顺序必须跟我们写进去的顺序一致。
传送跟接收自定义的List<MusicInfo> 的代码如下:
intent.putParcelableArrayListExtra(NatureService.MUSICS, (ArrayList<? extends Parcelable>) musicList);
musicList = intent.getParcelableArrayListExtra(MUSICS);
我也尝试过让MusicInfo 去实现Serializable 接口,然后放到Intent 中来传送,但是没办法实现,会爆出以下的Exception.
看 Log,其还是用parcelable 接口去解析的。
P.S. 我的MusicInfo是一个子类,所以必须是静态子类,否则定义public, static 的 CREATOR 接口中时,是会错误的。