设为首页 加入收藏

TOP

Android中的Parcelable接口(一)
2014-11-23 22:22:19 】 浏览:357
Tags:Android Parcelable 接口

比如Fragment1向Fragment2传递数据,下面是Fragment1中创建Fragment2并传送数据的方法:
Fragment2 fragment = new Fragment2();
Bundle bundle = new Bundle();
bundle.putParcelable("name", name);
fragment2.setArguments(bundle);

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container, fragment2)
.addToBackStack(null)
.commit();
在Fragment2中,直接得到这个Parcelable对象即可:


1 ParcelableName name = getArguments().getParcelable("name");
不过,既然Java已经有了Serializable,那还需要Parcelable干什么呢?而且Serializable接口使用起来也非常简洁。



原因有三个,第一是效率,第二是效率,第三还是效率:
1.Serializable用了很多反射,细心的人都知道,反射比正常的调用要慢100多倍


2.Serializable会创建很多临时对象,这些临时对象会导致很多次垃圾回收,影响效率


有细心的人士做过测试,基本上Parcelable要比Serializable快上10-20倍。下面这个图是比较结构,更详细信息可以参考Parcelable vs Serializable



下面是android.os.Parcelable接口的定义,相比java.io.Serializable要复杂很多,不过,为了效率,你也只能忍了。
public interface Parcelable {
public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
public int describeContents();
public void writeToParcel(Parcel dest, int flags);

public interface Creator {
public T createFromParcel(Parcel source);
public T[] newArray(int size);
}

public interface ClassLoaderCreator extends Creator {
public T createFromParcel(Parcel source, ClassLoader loader);
}
}
看起来你至少需要实现两个方法describeContents()和writeToParcel():


1.第一个方法返回数字,一般返回0就好,只有FileDescriptor有特殊,上面的常量有定义。至于这有什么用,我也没有找到相关的信息,如果有读者理解,请留言告知我。


2.第二个方法用于将对象写入到Parcel对象中。详见下面的例子。


接着自己来实现一个包含了姓和名两个String字段的对象,如下:
import android.os.Parcel;
import android.os.Parcelable;

public class ParcelableName implements Parcelable {
private String mSurname;
private String mGivenName;

public ParcelableName(String surname, String givenName) {
mSurname = surname;
mGivenName = givenName;
}

// 私有方法,因为我们不应该将参数是Parcel的构造函数暴露出去
private ParcelableName(Parcel source) {
this(source.readString(), source.readString());
}

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

public String getSurname() {
return mSurname;
}

public String getGivenName() {
return mGivenName;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mSurname);
dest.writeString(mGivenName);
}

// 通过这个接口来创建Parcel对象,调用了私有的构造函数
public static final Parcelable.Creator CREATOR
= new Creator() {

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

@Override
public ParcelableName[] newArray(int size) {
return new ParcelableName[0];
}
};
}
这里使用了Parcel.writeString()方法来将一个对象写入到序列化对象中,使用了Parcel.readString()从序列化对象中读取数据,一定要注意的是这里的写入和读取是有顺序的:先写的要先读。


注意,这里我们创建了一个私有的构造函数,这个构造函数的参数是Parcel对象,我们还创建了一个CREATOR的类变量,这个对象专门用于从序列化对象中创建ParcelableName对象,这是为了尽可能向外界隐藏序列化对象的实现细节,这种方式需要仔细琢磨,才能有所领悟。


值得提一下的是,Parcelable接口中还有一个ClassLoaderCreator接口,里面的createFromParcel()的第二个参数是一个ClassLoader对象,意味着我们可以反序列化不同的ClassLoader中的对象。


获取这段代码可以到:https://gist.github.com/zhlwish/3e2bbe9a15edf3b84ef7


这种代码写起来的确是挺麻烦的,有一个开源项目Parceler通过Anotation+代码生成的方法可以简化定义Parcelabl

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Swift 在对 Objective-C 改进的 6.. 下一篇C++函数与Java函数对比初识

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目