Android中的Parcelable接口

Android中的android.os.Parcelable接口用于替代Java序列化Serializable接口,Fragment以及Activtity之间都需要传递数据,有时甚至包含结构非常复杂的对象,这就需要先将这个对象序列化成二进制流,然后再进行传递了。

比如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对象即可:

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<T> {
        public T createFromParcel(Parcel source);
        public T[] newArray(int size);
    }
     
    public interface ClassLoaderCreator<T> extends Creator<T> {
        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<ParcelableName> CREATOR 
            = new Creator<ParcelableName>() {
     
            @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+代码生成的方法可以简化定义Parcelable对象的过程:

    @Parcel
    public class Example {
        String mSurname;
        String mGivenName;
    
        public Example(){ }
    
        public Example(String surname, String givenName) {
            mSurname = surname;
            mGivenName = givenName;
        }
    
        public String getSurname() { return mSurname; }
        public String getGivenName() { return mGivenName; }
    }

看起来简单多了,不过话说回来,如果你需要序列化的对象比较小,而且次数不多,不影响效率,你还是可以继续使用Serializable接口的,毕竟编码和维护的代价都小得多。

Android中的Parcelable接口,布布扣,bubuko.com

时间: 2024-10-22 02:56:04

Android中的Parcelable接口的相关文章

Android中的Parcelable接口和Serializable用法和区别

Parcelable接口: Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator inter

学习Android中的Parcelable接口

接触安桌不久,在之后很长的一段时间我将会一直在研究安桌开发.只是为了实现一下自己的想法. 1.首先要说parcelable之前必须要说一下,Serializable接口.看了很多教程,在说Activity数值传递的过程便是要先说Serializable接口,然后才是parvelable接口.两个接口相类似,有什么区别? Parcelable和Serializable的作用.效率.区别及选择: 1.作用 Serializable的作用是为了保存对象的属性到本地文件.数据库.网络流.rmi以方便数据

Android开发当中Parcelable接口的使用

对于Android来说传递复杂类型,主要是将自己的类转换为基础的字节数组,Activity之间传递数据是通过Intent实现的. Android序列化对象主要有两种方法,实现Serializable接口.或者实现Parcelable接口.实现Serializable接口是Java SE本身就支持的,而Parcelable是Android特有的功能,效率比实现Serializable接口高,而且还可以用在进程间通信(IPC)中.实现Serializable接口非常简单,声明一下就可以了.而实现Pa

Android中callback(接口回调)机制

事实上,callback 机制在Android 中无处不在,特别是以Handler.Callback.Listener这三个词结尾的,都是利用callback机制来实现的.比方点击事件onClickListener就是一个已经封装好的callback案例: tv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub

当在类中的 Parcelable 接口使用 ArrayList &lt; customObject &gt; android 系统: nullPointerException

我想使调用音乐使用 parcelable,所以我可以访问两个不同的活动中的音乐的实例的类.我不想使用可序列化的速度的目的.当我尝试将它使用传递时,我总是收到 nullPointerException: Intent in = getIntent(); thisInstance = (Music) in.getExtras().get("MusicInstance"); 音乐班: (ArrayList 是在底部的顶部和 parcelable 类) public class Music i

Android中使用OnClickListener接口实现按钮点击的低级失误

今天写了几行极为简单的代码,就是想implements  View.OnCLickListener.然后实现按钮点击操作.但是按钮却没有反应,找了五分钟还是没有结果. 以下是我的代码,希望大家不要嘲笑: XML布局如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:la

android中必备的接口回调用法

1 ,这个方法很常见,本人觉得也很实用,分享下吧 public class DirverDistanceTool { public void getDirverDistance(LatLng start, LatLng end,final OnDirverDistanceListener onDirverDistanceListener) { RoutePlanSearch mSearch = RoutePlanSearch.newInstance(); mSearch.setOnGetRout

Android Serializable与Parcelable原理与区别

一.序列化.反序列化是什么? (1) 名词解释 对象的序列化 : 把Java对象转换为字节序列并存储至一个储存媒介的过程.对象的反序列化:把字节序列恢复为Java对象的过程. (2) 序列化详细解释 对象的序列化涉及三个点关键点:Java对象.字节序列.存储. 1. Java对象的组成?Java对象包含变量与方法.但是序列与反序列化仅处理Java变量而不处理方法,序列与反序列化仅对数据进行处理. 2. 什么是字符序列?字符序列是两个词,字符是在计算机和电信领域中,字符(Character)是一个

Android中Serializable和Parcelable序列化对象详解

学习内容: 1.序列化的目的 2.Android中序列化的两种方式 3.Parcelable与Serializable的性能比较 4.Android中如何使用Parcelable进行序列化操作 5.Parcelable的工作原理 6.相关实例 1.序列化的目的 (1).永久的保存对象数据(将对象数据保存在文件当中,或者是磁盘中 (2).通过序列化操作将对象数据在网络上进行传输(由于网络传输是以字节流的方式对数据进行传输的.因此序列化的目的是将对象数据转换成字节流的形式) (3).将对象数据在进程