GVKun编程网logo

Android中的Parcelable是什么(android parcelable)

16

在这篇文章中,我们将为您详细介绍Android中的Parcelable是什么的内容,并且讨论关于androidparcelable的相关问题。此外,我们还会涉及一些关于(android)Parcela

在这篇文章中,我们将为您详细介绍Android中的Parcelable是什么的内容,并且讨论关于android parcelable的相关问题。此外,我们还会涉及一些关于(android) Parcelable 接口的使用、Android Parcelable、Android Parcelable 和 Serializable 的区别、Android Parcelable 和 Serializable 的区别 (转载)的知识,以帮助您更全面地了解这个主题。

本文目录一览:

Android中的Parcelable是什么(android parcelable)

Android中的Parcelable是什么(android parcelable)

public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}

     public MyParcelable[] newArray(int size) {         return new MyParcelable[size];     }  };  private MyParcelable(Parcel in) {     mData = in.readInt();  }}

在我的Android课程中,讲师使用了这段代码,他们并没有对此做充分的解释。如何解释此代码?我尝试阅读文档,但无法解释。

答案1

小编典典

这个概念叫做
包裹

Parcelable是Java
Serializable的Android实现。它假定某种结构和处理方式。与标准Java序列化相比,这种方式可以相对快速地处理Parcelable。

为了将您的自定义对象解析为其他组件,他们需要实现android.os.Parcelable接口。它还必须提供一个称为CREATOR的静态最终方法,该方法必须实现Parcelable.Creator接口。

您编写的代码将成为您的模型类。

您可以在Activity中使用Parcelable,例如:

intent.putExtra("student", new Student("1")); //size which you are storing

并得到这个对象:

Bundle data = getIntent().getExtras();Student student = (Student) data.getParcelable("student");

学生是模型班级的名称。用你的代替它。

简单来说,Parcelable用于将模型类的整个对象发送到另一个页面。

在您的代码中,它在模型中,并且将int值 大小 存储到Parcelable对象中,以便在其他活动中发送和检索。

参考:

教程1

教程2

教程3

(android) Parcelable 接口的使用

(android) Parcelable 接口的使用

什么是 Parcelable ?

     Parcelable, 定义了将数据写入 Parcel,和从 Parcel 中读出的接口。一个实体(用类来表示),如果需要封装到消息中去,就必须实现这一接口,实现了这一接口,该实体就成为 “可打包的” 了。

Parcelable 传递对象

    Android 序列化对象主要有两种方法:

    1. 实现 Serializable 接口,实现 Serializable 接口是 JavaSE 本身就支持的;

    2. 实现 Parcelable 接口,Parcelable 是 Android 特有的功能,效率比实现 Serializable 接口高,像用于 Intent 数据传递也都支持,而且还可以用在进程间通信 (IPC),

      除了基本类型外,只有实现了 Parcelable 接口的类才能被放入 Parcel 中。

Parcelable 接口定义

public interface Parcelable {
    //内容描述接口,基本不用管
    public int describeContents();
    //写入接口函数,打包
    public void writeToParcel(Parcel dest, int flags);
     //读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。因为实现类在这里还是不可知的,所以需要用到模板的方式,继承类名通过模板参数传入。
    //为了能够实现模板参数的传入,这里定义Creator嵌入接口,内含两个接口函数分别返回单个和多个继承类实例。
    public interface Creator<T{
           public T createFromParcel(Parcel source);
           public T[] newArray(int size);
       }

怎么实现 Parcelable 接口?

从 parcelable 接口定义中,我们可以看到,实现 parcelable 接口,需要我们实现下面几个方法:

   1.describeContents 方法。内容接口描述,默认返回 0 就可以;

   2.writeToParcel 方法。该方法将类的数据写入外部提供的 Parcel 中。即打包需要传递的数据到 Parcel 容器保存,以便从 parcel 容器获取数据,该方法声明如下:

     writeToParcel (Parcel dest, int flags) 具体参数含义见 javadoc

   3. 静态的 Parcelable.Creator 接口,本接口有两个方法:

     createFromParcel (Parcel in)  从 Parcel 容器中读取传递数据值,封装成 Parcelable 对象返回逻辑层。

     newArray (int size) 创建一个类型为 T,长度为 size 的数组,仅一句话(return new T [size]) 即可。方法是供外部类反序列化本类数组使用。

代码实现

  1. 封装数据,把实现 parcelable 接口的 Person 对象传递到 TwoActivity 里;

public class DemoActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // 封装数据
        Person p = new Person();
        p.setId(1);
        p.setName("xiaoming");
        // 用Intent传递Person对象
        Intent i = new Intent(this, TwoActivity.class);
        i.putExtra("Person", p);
        startActivity(i);
    }
}

2.TwoActivity 获取数据,从 DemoActivity 传递的 Person 对象给解析,并打印;

public class TwoActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        
        Person p = (Person)getIntent().getParcelableExtra("Person");
        
        System.out.println("p_id"+p.getId());
        System.out.println("p_name"+p.getName());
    }
}

3.parcelable 接口的实现

public class Person implements Parcelable{
    
    // 成员变量
    private int id;
    private String name;
    
    // 1.必须实现Parcelable.Creator接口,否则在获取Person数据的时候,会报错,如下:
    // android.os.BadParcelableException:
    // Parcelable protocol requires a Parcelable.Creator object called  CREATOR on class com.um.demo.Person
    // 2.这个接口实现了从Percel容器读取Person数据,并返回Person对象给逻辑层使用
    // 3.实现Parcelable.Creator接口对象名必须为CREATOR,不如同样会报错上面所提到的错;
    // 4.在读取Parcel容器里的数据事,必须按成员变量声明的顺序读取数据,不然会出现获取数据出错
    // 5.反序列化对象
    public static final Parcelable.Creator<Person> CREATOR = new Creator(){

        @Override
        public Person createFromParcel(Parcel source) {
            // TODO Auto-generated method stub
            // 必须按成员变量声明的顺序读取数据,不然会出现获取数据出错
            Person p = new Person();
            p.setId(source.readInt());
            p.setName(source.readString());
            return p;
        }

        @Override
        public Person[] newArray(int size) {
            // TODO Auto-generated method stub
            return new Person[size];
        }
    };
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        // TODO Auto-generated method stub
        // 1.必须按成员变量声明的顺序封装数据,不然会出现获取数据出错
        // 2.序列化对象
        dest.writeInt(id);
        dest.writeString(name);
    }
}


Android Parcelable

Android Parcelable

Parcelable(SDK)

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.Creatorinterface.


Passing data between activities is quite easy. 

You would normally do that using the Bundle packed into an intent. But sometimes you need to pass complex objects from one activity to another. 

One workaround would be to keep a static instance of the object int your Activity and access it from you new Activity. This might help, but it''s definitely not a good way to do this. 

To pass such objects directly through the Bundle, your class would need to implement the Parcelable interface. 


Example:

MainActivity, SubActivity, Person


MainActivity

源码打印?
  1. package com.learn;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.widget.Button;  
  10.   
  11. public class MainActivity extends Activity implements OnClickListener {  
  12.   
  13.     private static final String TAG = "Parcelable";  
  14.       
  15.     public static final String KEY = "key";  
  16.     private Button btn;  
  17.       
  18.       
  19.     @Override  
  20.     public void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.main);  
  23.   
  24.         Log.d(TAG, "MainActivity");  
  25.           
  26.         btn = (Button)findViewById(R.id.btn);  
  27.         btn.setOnClickListener(this);  
  28.           
  29.     }  
  30.       
  31.       
  32.     @Override  
  33.     public void onClick(View v) {  
  34.   
  35.         Log.d(TAG, "onClick");  
  36.           
  37.         if(R.id.btn == v.getId()){  
  38.               
  39.             Person mPerson = new Person();  
  40.             mPerson.setName("Bill");  
  41.             mPerson.setAge(22);  
  42.               
  43.             Bundle bundle = new Bundle();  
  44.             bundle.putParcelable(KEY, mPerson);     // mPerson -> Parcelable  
  45.   
  46.             Log.d(TAG, "mPerson=" + mPerson);  
  47.               
  48.             Intent intent = new Intent(this, SubActivity.class);  
  49.             intent.putExtras(bundle);  
  50.             startActivity(intent);  
  51.   
  52.             Log.d(TAG, "startActivity");  
  53.         }  
  54.           
  55.     }  
  56. }  
package com.learn;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private static final String TAG = "Parcelable";
	
	public static final String KEY = "key";
	private Button btn;
	
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Log.d(TAG, "MainActivity");
        
        btn = (Button)findViewById(R.id.btn);
    	btn.setOnClickListener(this);
    	
    }
    
    
    @Override
    public void onClick(View v) {

        Log.d(TAG, "onClick");
        
    	if(R.id.btn == v.getId()){
    		
    		Person mPerson = new Person();
    		mPerson.setName("Bill");
    		mPerson.setAge(22);
    		
    		Bundle bundle = new Bundle();
    		bundle.putParcelable(KEY, mPerson);		// mPerson -> Parcelable

            Log.d(TAG, "mPerson=" + mPerson);
    		
    		Intent intent = new Intent(this, SubActivity.class);
    		intent.putExtras(bundle);
    		startActivity(intent);

            Log.d(TAG, "startActivity");
    	}
    	
    }
}

SubActivity

源码打印?
  1. package com.learn;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Parcelable;  
  6. import android.util.Log;  
  7. import android.widget.TextView;  
  8.   
  9. public class SubActivity extends Activity {  
  10.   
  11.     private static final String TAG = "Parcelable";  
  12.       
  13.     private TextView tv;  
  14.   
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState){  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);  
  19.   
  20.         Log.d(TAG, "SubActivity");  
  21.           
  22.         Parcelable parcelable = getIntent().getParcelableExtra(MainActivity.KEY);  
  23.         Person mPerson = (Person)parcelable;        // Parcelable -> Person  
  24.   
  25.         Log.d(TAG, "parcelable=" + parcelable + "; mPerson=" + mPerson);  
  26.           
  27.         tv = (TextView)findViewById(R.id.tv);  
  28.         tv.setText("name=" + mPerson.getName() + "; age=" + mPerson.getAge());  
  29.     }  
  30.       
  31. }  
package com.learn;

import android.app.Activity;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.widget.TextView;

public class SubActivity extends Activity {

	private static final String TAG = "Parcelable";
	
	private TextView tv;

	@Override
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

        Log.d(TAG, "SubActivity");
        
		Parcelable parcelable = getIntent().getParcelableExtra(MainActivity.KEY);
		Person mPerson = (Person)parcelable;		// Parcelable -> Person

        Log.d(TAG, "parcelable=" + parcelable + "; mPerson=" + mPerson);
        
		tv = (TextView)findViewById(R.id.tv);
		tv.setText("name=" + mPerson.getName() + "; age=" + mPerson.getAge());
	}
	
}

Person

源码打印?
  1. package com.learn;  
  2.   
  3. import android.os.Parcel;  
  4. import android.os.Parcelable;  
  5. import android.util.Log;  
  6.   
  7. public class Person implements Parcelable{  
  8.   
  9.     private static final String TAG = "Parcelable";  
  10.       
  11.     private String name;  
  12.     private int age;  
  13.       
  14.     public Person(){  
  15.           
  16.     }  
  17.   
  18.     public void setName(String name){  
  19.         this.name = name;  
  20.     }  
  21.       
  22.     public String getName(){  
  23.         return this.name;  
  24.     }  
  25.       
  26.     public void setAge(int age){  
  27.         this.age = age;  
  28.     }  
  29.       
  30.     public int getAge(){  
  31.         return this.age;  
  32.     }  
  33.       
  34.       
  35.     public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {  
  36.   
  37.         @Override  
  38.         public Person createFromParcel(Parcel source) {  
  39.   
  40.             Log.d(TAG, "createFromParcel(Parcel source)");  
  41.               
  42.             Person mPerson = new Person();  
  43.               
  44.             mPerson.name = source.readString();  
  45.             mPerson.age = source.readInt();  
  46.               
  47.             return mPerson;  
  48.         }  
  49.   
  50.         @Override  
  51.         public Person[] newArray(int size) {  
  52.   
  53.             Log.d(TAG, "newArray(int size)");  
  54.               
  55.             return new Person[size];  
  56.         }  
  57.           
  58.     };  
  59.       
  60.     @Override  
  61.     public int describeContents() {  
  62.   
  63.         Log.d(TAG, "describeContents()");  
  64.           
  65.         return 0;  
  66.     }  
  67.   
  68.     @Override  
  69.     public void writeToParcel(Parcel dest, int flags) {  
  70.   
  71.         Log.d(TAG, "writeToParcel(Parcel dest, int flags)");  
  72.           
  73.         dest.writeString(name);  
  74.         dest.writeInt(age);  
  75.     }  
  76.       
  77. }  
package com.learn;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

public class Person implements Parcelable{

	private static final String TAG = "Parcelable";
	
	private String name;
	private int age;
	
	public Person(){
		
	}

	public void setName(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public void setAge(int age){
		this.age = age;
	}
	
	public int getAge(){
		return this.age;
	}
	
	
	public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {

		@Override
		public Person createFromParcel(Parcel source) {

            Log.d(TAG, "createFromParcel(Parcel source)");
            
			Person mPerson = new Person();
			
			mPerson.name = source.readString();
			mPerson.age = source.readInt();
			
			return mPerson;
		}

		@Override
		public Person[] newArray(int size) {

            Log.d(TAG, "newArray(int size)");
            
			return new Person[size];
		}
		
	};
	
	@Override
	public int describeContents() {

        Log.d(TAG, "describeContents()");
        
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {

        Log.d(TAG, "writeToParcel(Parcel dest, int flags)");
        
		dest.writeString(name);
		dest.writeInt(age);
	}
	
}

main.xml

源码打印?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent">  
  6.       
  7.     <TextView    
  8.         android:id="@+id/tv"  
  9.         android:layout_width="fill_parent"   
  10.         android:layout_height="wrap_content"   
  11.         android:text="@string/hello" />  
  12.       
  13.     <Button android:id="@+id/btn"  
  14.         android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content"  
  16.         android:text="Parcelable" />  
  17.       
  18. </LinearLayout>  
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    
	<TextView  
		android:id="@+id/tv"
    	android:layout_width="fill_parent" 
    	android:layout_height="wrap_content" 
    	android:text="@string/hello" />
    
    <Button android:id="@+id/btn"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:text="Parcelable" />
    
</LinearLayout>

Running Result


click, then



Log

源码打印?
  1. D/Parcelable(  487): MainActivity  
  2. D/Parcelable(  487): onClick  
  3. D/Parcelable(  487): mPerson=com.learn.Person@40520b98  
  4. D/Parcelable(  487): writeToParcel(Parcel dest, int flags)  
  5. D/Parcelable(  487): startActivity  
  6. D/Parcelable(  487): SubActivity  
  7. D/Parcelable(  487): createFromParcel(Parcel source)  
  8. D/Parcelable(  487): parcelable=com.learn.Person@405269f8; mPerson=com.learn.Person@405269f8  
D/Parcelable(  487): MainActivity
D/Parcelable(  487): onClick
D/Parcelable(  487): mPerson=com.learn.Person@40520b98
D/Parcelable(  487): writeToParcel(Parcel dest, int flags)
D/Parcelable(  487): startActivity
D/Parcelable(  487): SubActivity
D/Parcelable(  487): createFromParcel(Parcel source)
D/Parcelable(  487): parcelable=com.learn.Person@405269f8; mPerson=com.learn.Person@405269f8


Analyse

writeToParcel(Parcel dest, int flags)         ----          bundle.putParcelable(KEY, mPerson)

createFromParcel(Parcel source)             ----          (Person)getIntent().getParcelableExtra(MainActivity.KEY)

source                                                        ----          dest


Download


Parcelable - How to do that in Android

Writing Parcelable classes for Android


原文链接: http://blog.csdn.net/sunboy_2050/article/details/6949809

Android Parcelable 和 Serializable 的区别

Android Parcelable 和 Serializable 的区别

学习内容:

1. 序列化的目的

2.Android 中序列化的两种方式

3.Parcelable 与 Serializable 的性能比较

4.Android 中如何使用 Parcelable 进行序列化操作

5.Parcelable 的工作原理

6. 相关实例

 

1. 序列化的目的

  (1). 永久的保存对象数据 (将对象数据保存在文件当中,或者是磁盘中

  (2). 通过序列化操作将对象数据在网络上进行传输 (由于网络传输是以字节流的方式对数据进行传输的。因此序列化的目的是将对象数据转换成字节流的形式)

  (3). 将对象数据在进程之间进行传递 (Activity 之间传递对象数据时,需要在当前的 Activity 中对对象数据进行序列化操作。在另一个 Activity 中需要进行反序列化操作讲数据取出)

  (4).Java 平台允许我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM 的生命周期更长(即每个对象都在 JVM 中)但在现实应用中,就可能要停止 JVM 运行,但有要保存某些指定的对象,并在将来重新读取被保存的对象。这是 Java 对象序列化就能够实现该功能。(可选择入数据库、或文件的形式保存)

  (5). 序列化对象的时候只是针对变量进行序列化,不针对方法进行序列化.

  (6). 在 Intent 之间,基本的数据类型直接进行相关传递即可,但是一旦数据类型比较复杂的时候,就需要进行序列化操作了.

 

2.Android 中实现序列化的两种方式
(1).Implements Serializable 接口 (声明一下即可)
Serializable 的简单实例:

public class Person implements Serializable{
 private static final long serialVersionUID = -7060210544600464481L;
 private String name;
 private int age;
  
 public String getName(){
  return name;
 }
  
 public void setName(String name){
  this.name = name;
 }
  
 public int getAge(){
  return age;
 }
  
 public void setAge(int age){
  this.age = age;
 }
}

(2).Implements Parcelable 接口 (不仅仅需要声明,还需要实现内部的相应方法)
Parcelable 的简单实例:

注:写入数据的顺序和读出数据的顺序必须是相同的.

public class Book implements Parcelable{
 private String bookName;
 private String author;
 private int publishDate;
  
 public Book(){
   
 }
  
 public String getBookName(){
  return bookName;
 }
  
 public void setBookName(String bookName){
  this.bookName = bookName;
 }
  
 public String getAuthor(){
  return author;
 }
  
 public void setAuthor(String author){
  this.author = author;
 }
  
 public int getPublishDate(){
  return publishDate;
 }
  
 public void setPublishDate(int publishDate){
  this.publishDate = publishDate;
 }
  
 @Override
 public int describeContents(){
  return 0;
 }
  
 @Override
 public void writeToParcel(Parcel out, int flags){
  out.writeString(bookName);
  out.writeString(author);
  out.writeInt(publishDate);
 }
  
 public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
   
     @Override
  public Book[] newArray(int size){
   return new Book[size];
  }
   
  @Override
  public Book createFromParcel(Parcel in){
   return new Book(in);
  }
 };
  
 public Book(Parcel in){
  //如果元素数据是list类型的时候需要: lits = new ArrayList<?> in.readList(list); 
  //否则会出现空指针异常.并且读出和写入的数据类型必须相同.如果不想对部分关键字进行序列化,可以使用transient关键字来修饰以及static修饰.
  bookName = in.readString();
  author = in.readString();
  publishDate = in.readInt();
 }
}

我们知道在 Java 应用程序当中对类进行序列化操作只需要实现 Serializable 接口就可以,由系统来完成序列化和反序列化操作,但是在 Android 中序列化操作有另外一种方式来完成,那就是实现 Parcelable 接口。也是 Android 中特有的接口来实现类的序列化操作。原因是 Parcelable 的性能要强于 Serializable. 因此在绝大多数的情况下,Android 还是推荐使用 Parcelable 来完成对类的序列化操作的.

3.Parcelable 与 Serializable 的性能比较

首先 Parcelable 的性能要强于 Serializable 的原因我需要简单的阐述一下

  1). 在内存的使用中,前者在性能方面要强于后者

  2). 后者在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制) 从而导致 GC 的频繁调用,因此在性能上会稍微逊色

  3). Parcelable 是以 Ibinder 作为信息载体的。在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android 推荐使用 Parcelable, 既然是内存方面比价有优势,那么自然就要优先选择.

  4). 在读写数据的时候,Parcelable 是在内存中直接进行读写,而 Serializable 是通过使用 IO 流的形式将数据读写入在硬盘上.

  但是:虽然 Parcelable 的性能要强于 Serializable, 但是仍然有特殊的情况需要使用 Serializable, 而不去使用 Parcelable, 因为 Parcelable 无法将数据进行持久化,因此在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行持久化.(原因是在不同的 Android 版本当中,Parcelable 可能会不同,因此数据的持久化方面仍然是使用 Serializable)

  速度测试:

  测试方法:

1)、通过将一个对象放到一个 bundle 里面然后调用 Bundle#writeToParcel (Parcel, int) 方法来模拟传递对象给一个 activity 的过程,然后再把这个对象取出来。

2)、在一个循环里面运行 1000 次。

3)、两种方法分别运行 10 次来减少内存整理,cpu 被其他应用占用等情况的干扰。

4)、参与测试的对象就是上面的相关代码

5)、在多种 Android 软硬件环境上进行测试

  • LG Nexus 4 – Android 4.2.2
  • Samsung Nexus 10 – Android 4.2.2
  • HTC Desire Z – Android 2.3.3 

 结果如图:

性能差异:

Nexus 10

Serializable: 1.0004ms,  Parcelable: 0.0850ms – 提升 10.16 倍。

Nexus 4

Serializable: 1.8539ms – Parcelable: 0.1824ms – 提升 11.80 倍。

Desire Z

Serializable: 5.1224ms – Parcelable: 0.2938ms – 提升 17.36 倍。

由此可以得出: Parcelable 比 Serializable 快了 10 多倍。

  从相对的比较我们可以看出,Parcelable 的性能要比 Serializable 要优秀的多,因此在 Android 中进行序列化操作的时候,我们需要尽可能的选择前者,需要花上大量的时间去实现 Parcelable 接口中的内部方法.

4.Android 中如何使用 Parcelable 进行序列化操作

说了这么多,我们还是来看看 Android 中如何去使用 Parcelable 实现类的序列化操作吧.
 Implements Parcelable 的时候需要实现内部的方法:

1).writeToParcel 将对象数据序列化成一个 Parcel 对象 (序列化之后成为 Parcel 对象。以便 Parcel 容器取出数据)

2). 重写 describeContents 方法,默认值为 0

3).Public static final Parcelable.Creator<T>CREATOR (将 Parcel 容器中的数据转换成对象数据) 同时需要实现两个方法:
  3.1 CreateFromParcel (从 Parcel 容器中取出数据并进行转换.) 
  3.2 newArray (int size) 返回对象数据的大小

 因此,很明显实现 Parcelable 并不容易。实现 Parcelable 接口需要写大量的模板代码,这使得对象代码变得难以阅读和维护。具体的实例就是上面 Parcelable 的实例代码。就不进行列举了.(有兴趣的可以去看看 Android 中 NetWorkInfo 的源代码,是关于网络连接额外信息的一个相关类,内部就实现了序列化操作。大家可以去看看)

5.Parcelable 的工作原理

 无论是对数据的读还是写都需要使用 Parcel 作为中间层将数据进行传递.Parcel 涉及到的东西就是与 C++ 底层有关了。都是使用 JNI. 在 Java 应用层是先创建 Parcel (Java) 对象,然后再调用相关的读写操作的时候。就拿读写 32 为 Int 数据来说吧:

static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz){
 Parcel* parcel = parcelForJavaObject(env, clazz);
 if (parcel != NULL) {
  return parcel->readInt32();
 }
 return 0;
}

调用的方法就是这个过程,首先是将 Parcel (Java) 对象转换成 Parcel (C++) 对象,然后被封装在 Parcel 中的相关数据由 C++ 底层来完成数据的序列化操作.

status_t Parcel::writeInt32(int32_t val){
 return writeAligned(val);
} 
template<class t="">
status_t Parcel::writeAligned(T val) {
 COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
  
 if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
  *reinterpret_cast<t*>(mData+mDataPos) = val;
  return finishWrite(sizeof(val));
 }
  
 status_t err = growData(sizeof(val));
 if (err == NO_ERROR) goto restart_write;
 return err;
}
真正的读写过程是由下面的源代码来完成的.
status_t Parcel::continueWrite(size_t desired)
{
 // If shrinking, first adjust for any objects that appear
 // after the new data size.
 size_t objectsSize = mObjectsSize;
 if (desired < mDataSize) {
  if (desired == 0) {
   objectsSize = 0;
  } else {
   while (objectsSize > 0) {
    if (mObjects[objectsSize-1] < desired)
     break;
    objectsSize--;
   }
  }
 }
  
 if (mOwner) {
  // If the size is going to zero, just release the owner''s data.
  if (desired == 0) {
   freeData();
   return NO_ERROR;
  }
 
  // If there is a different owner, we need to take
  // posession.
  uint8_t* data = (uint8_t*)malloc(desired);
  if (!data) {
   mError = NO_MEMORY;
   return NO_MEMORY;
  }
  size_t* objects = NULL;
   
  if (objectsSize) {
   objects = (size_t*)malloc(objectsSize*sizeof(size_t));
   if (!objects) {
    mError = NO_MEMORY;
    return NO_MEMORY;
   }
 
   // Little hack to only acquire references on objects
   // we will be keeping.
   size_t oldObjectsSize = mObjectsSize;
   mObjectsSize = objectsSize;
   acquireObjects();
   mObjectsSize = oldObjectsSize;
  }
   
  if (mData) {
   memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
  }
  if (objects && mObjects) {
   memcpy(objects, mObjects, objectsSize*sizeof(size_t));
  }
  //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
  mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
  mOwner = NULL;
 
  mData = data;
  mObjects = objects;
  mDataSize = (mDataSize < desired) ? mDataSize : desired;
  ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  mDataCapacity = desired;
  mObjectsSize = mObjectsCapacity = objectsSize;
  mNextObjectHint = 0;
 
 } else if (mData) {
  if (objectsSize < mObjectsSize) {
   // Need to release refs on any objects we are dropping.
   const sp<ProcessState> proc(ProcessState::self());
   for (size_t i=objectsSize; i<mObjectsSize; i++) {
    const flat_binder_object* flat
     = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
    if (flat->type == BINDER_TYPE_FD) {
     // will need to rescan because we may have lopped off the only FDs
     mFdsKnown = false;
    }
    release_object(proc, *flat, this);
   }
   size_t* objects =
    (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
   if (objects) {
    mObjects = objects;
   }
   mObjectsSize = objectsSize;
   mNextObjectHint = 0;
  }
 
  // We own the data, so we can just do a realloc().
  if (desired > mDataCapacity) {
   uint8_t* data = (uint8_t*)realloc(mData, desired);
   if (data) {
    mData = data;
    mDataCapacity = desired;
   } else if (desired > mDataCapacity) {
    mError = NO_MEMORY;
    return NO_MEMORY;
   }
  } else {
   if (mDataSize > desired) {
    mDataSize = desired;
    ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
   }
   if (mDataPos > desired) {
    mDataPos = desired;
    ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
   }
  }
   
 } else {
  // This is the first data. Easy!
  uint8_t* data = (uint8_t*)malloc(desired);
  if (!data) {
   mError = NO_MEMORY;
   return NO_MEMORY;
  }
   
  if(!(mDataCapacity == 0 && mObjects == NULL
    && mObjectsCapacity == 0)) {
   ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
  }
   
  mData = data;
  mDataSize = mDataPos = 0;
  ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
  mDataCapacity = desired;
 }
 
 return NO_ERROR;
}

1). 整个读写全是在内存中进行,主要是通过 malloc ()、realloc ()、memcpy () 等内存操作进行,所以效率比 JAVA 序列化中使用外部存储器会高很多

2). 读写时是 4 字节对齐的,可以看到 #define PAD_SIZE (s) (((s)+3)&~3) 这句宏定义就是在做这件事情

3). 如果预分配的空间不够时 newSize = ((mDataSize+len)*3)/2; 会一次多分配 50%

4). 对于普通数据,使用的是 mData 内存地址,对于 IBinder 类型的数据以及 FileDescriptor 使用的是 mObjects 内存地址。后者是通过 flatten_binder () 和 unflatten_binder () 实现的,目的是反序列化时读出的对象就是原对象而不用重新 new 一个新对象。
6. 相关实例

最后上一个例子..

首先是序列化的类 Book.class

public class Book implements Parcelable{
 private String bookName;
 private String author;
 private int publishDate;
  
 public Book(){
   
 }
  
 public String getBookName(){
  return bookName;
 }
  
 public void setBookName(String bookName){
  this.bookName = bookName;
 }
  
 public String getAuthor(){
  return author;
 }
  
 public void setAuthor(String author){
  this.author = author;
 }
  
 public int getPublishDate(){
  return publishDate;
 }
  
 public void setPublishDate(int publishDate){
  this.publishDate = publishDate;
 }
  
 @Override
 public int describeContents(){
  return 0;
 }
  
 @Override
 public void writeToParcel(Parcel out, int flags){
  out.writeString(bookName);
  out.writeString(author);
  out.writeInt(publishDate);
 }
  
 public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
   
     @Override
  public Book[] newArray(int size){
   return new Book[size];
  }
   
  @Override
  public Book createFromParcel(Parcel in){
   return new Book(in);
  }
 };
  
 public Book(Parcel in){
  //如果元素数据是list类型的时候需要: lits = new ArrayList<?> in.readList(list); 否则会出现空指针异常.并且读出和写入的数据类型必须相同.如果不想对部分关键字进行序列化,可以使用transient关键字来修饰以及static修饰.
  bookName = in.readString();
  author = in.readString();
  publishDate = in.readInt();
 }
}

第一个 Activity,MainActivity

Book book = new Book();
book.setBookname("Darker");
book.setBookauthor("me");
book.setPublishDate(20);
Bundle bundle = new Bundle();
bundle.putParcelable("book", book);
Intent intent = new Intent(MainActivity.this,AnotherActivity.class);
intent.putExtras(bundle);

第二个 Activity,AnotherActivity

Intent intent = getIntent();
Bundle bun = intent.getExtras();
Book book = bun.getParcelable("book");
System.out.println(book);

总结:Java 应用程序中有 Serializable 来实现序列化操作,Android 中有 Parcelable 来实现序列化操作,相关的性能也作出了比较,因此在 Android 中除了对数据持久化的时候需要使用到 Serializable 来实现序列化操作,其他的时候我们仍然需要使用 Parcelable 来实现序列化操作,因为在 Android 中效率并不是最重要的,而是内存,通过比较 Parcelable 在效率和内存上都要优秀与 Serializable, 尽管 Parcelable 实现起来比较复杂,但是如果我们想要成为一名优秀的 Android 软件工程师,那么我们就需要勤快一些去实现 Parcelable, 而不是偷懒与实现 Serializable. 当然实现后者也不是不行,关键在于我们头脑中的那一份思想。

Android Parcelable 和 Serializable 的区别 (转载)

Android Parcelable 和 Serializable 的区别 (转载)

1、作用

Serializable 的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi 以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而 Android 的 Parcelable 的设计初衷是因为 Serializable 效率过慢,为了在程序内不同组件间以及不同 Android 程序间 (AIDL) 高效的传输数据而设计,这些数据仅在内存中存在,Parcelable 是通过 IBinder 通信的消息的载体。

从上面的设计上我们就可以看出优劣了。

 

2、效率及选择

Parcelable 的性能比 Serializable 好,在内存开销方面较小,所以在内存间数据传输时推荐使用 Parcelable,如 activity 间传输数据,而 Serializable 可将数据持久化方便保存,所以在需要保存或网络传输数据时选择 Serializable,因为 android 不同版本 Parcelable 可能不同,所以不推荐使用 Parcelable 进行数据持久化

 

3、编程实现

对于 Serializable,类只需要实现 Serializable 接口,并提供一个序列化版本 id (serialVersionUID) 即可。而 Parcelable 则需要实现 writeToParcel、describeContents 函数以及静态的 CREATOR 变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现

Parcelable 的一个实现例子如下

复制代码
public class MyParcelable implements Parcelable { private int mData; private String mStr; public int describeContents() { return 0;
     } // 写数据进行保存 public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
         out.writeString(mStr);
     } // 用来创建自定义的Parcelable的对象 public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() { public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in);
         } public MyParcelable[] newArray(int size) { return new MyParcelable[size];
         }
     }; // 读数据进行恢复 private MyParcelable(Parcel in) {
         mData = in.readInt();
         mStr = in.readString();
     }
 }
复制代码

从上面我们可以看出 Parcel 的写入和读出顺序是一致的。如果元素是 list 读出时需要先 new 一个 ArrayList 传入,否则会报空指针异常。如下:

list = new ArrayList<String>();
in.readStringList(list);

 PS: 在自己使用时,read 数据时误将前面 int 数据当作 long 读出,结果后面的顺序错乱,报如下异常,当类字段较多时务必保持写入和读取的类型及顺序一致

11-21 20:14:10.317: E/AndroidRuntime(21114): Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@4126ed60: Unmarshalling unknown type code 3014773 at offset 164

 

4、高级功能上

Serializable 序列化不保存静态变量,可以使用 Transient 关键字对部分字段不进行序列化,也可以覆盖 writeObject、readObject 方法以实现序列化过程自定义

关于Android中的Parcelable是什么android parcelable的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于(android) Parcelable 接口的使用、Android Parcelable、Android Parcelable 和 Serializable 的区别、Android Parcelable 和 Serializable 的区别 (转载)等相关知识的信息别忘了在本站进行查找喔。

本文标签: