1. 程式人生 > >Android中的序列化機制——Parcel與Parcelable

Android中的序列化機制——Parcel與Parcelable


當我們在呼叫遠端方法時,需要在程序間傳遞引數以及返回結果。這種類似的處理方式,需要把資料與程序相關性去除,變成一種中間形式,然後按統一的介面進行讀寫操作。這樣的機制,一般在高階程式語言裡都被稱為序列化。


在Android世界裡處理資料的序列化操作的,使用了一種Parcel類,而能夠處理資料序列能力,則是實現Parcelable介面來實現。於是,當我們需要在程序間傳輸一個物件,則實現這一物件的類必須實現Parcelable接口裡定義的相應屬性或方法,而在使用這一物件時,則可以使用一個Parcel引用來處理傳輸時的基本操作。

ParcelSerialize很類似,只是它是在記憶體中完成的序列化和反序列化,利用的是連續的記憶體空間,因此會更加高效。


1. 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 interface。


2.實現Parcelable就是為了進行序列化,那麼,為什麼要序列化?
1)永久性儲存物件,儲存物件的位元組序列到本地檔案中;
2)通過序列化物件在網路中傳遞物件;
3)通過序列化在程序間傳遞物件。


3.實現序列化的方法

Android中實現序列化有兩個選擇:一是實現Serializable介面(是JavaSE本身就支援的),一是實現Parcelable介面(是Android特有功能,效率比實現Serializable介面高效,可用於Intent資料傳遞,也可以用於程序間通訊(IPC))。實現Serializable介面非常簡單,宣告一下就可以了,而實現Parcelable介面稍微複雜一些,但效率更高,推薦用這種方法提高效能。
注:Android中Intent傳遞物件有兩種方法:一是Bundle.putSerializable(Key,Object),另一種是Bundle.putParcelable(Key,Object)。當然這些Object是有一定的條件的,前者是實現了Serializable介面,而後者是實現了Parcelable介面。


4.選擇序列化方法的原則

1)在使用記憶體的時候,Parcelable比Serializable效能高,所以推薦使用Parcelable。
2)Serializable在序列化的時候會產生大量的臨時變數,從而引起頻繁的GC。
3)Parcelable不能使用在要將資料儲存在磁碟上的情況,因為Parcelable不能很好的保證資料的持續性在外界有變化的情況下。儘管Serializable效率低點,但此時還是建議使用Serializable 。


5.應用場景

需要在多個部件(Activity或Service)之間通過Intent傳遞一些資料,簡單型別(如:數字、字串)的可以直接放入Intent。複雜型別必須實現Parcelable介面。

6.Serializable實現與Parcelabel實現的區別
1)Serializable的實現,只需要implements  Serializable 即可。這只是給物件打了一個標記,系統會自動將其序列化。
2)Parcelabel的實現,不僅需要implements  Parcelabel,還需要在類中新增一個靜態成員變數CREATOR,這個變數需要實現 Parcelable.Creator 介面。

1)建立Person類,實現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)建立Book類,實現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)
    {
        bookName = in.readString();
        author = in.readString();
        publishDate = in.readInt();
    }
}
1、describeContents(),Parcelabl所需要的介面方法之一,必須實現。這一方法作用很簡單,就是通過返回的整形來描述這一Parcel是起什麼作用的,通過這一整形每個bit來描述其型別,一般會返回0。
2、writeToParcel(),Parcelabl所需要的介面方法之二,必須實現。writeToParcel()方法的作用是傳送,就是將類所需要傳輸的屬性寫到Parcel裡,被用來提供傳送功能的Parcel,會作為第一個引數傳入,於是在這個方法裡都是使用writeInt()、writeLong()寫入到Parcel裡。這一方法的第二引數是一個flag值,可以用來指定這樣的傳送是單向還是雙向的,可以與aidl的in、out、inout三種限定符匹配。
3、CREATOR物件,Parcelable介面所需要的第三項,必須提供實現,但這是一個是介面物件。正如我們看到的,這一CREATOR物件,是使用模板類Parcelable.Creator,套用到TaskInfo來得到的,Parcelable.Creator<TaskInfo>。這個CREATOR物件在很大程度上是一個工廠(Factory)類,用於遠端物件在接收端的建立。從某種意義上來說,writeToParcel()與CREATOR是一一對應的,傳送端程序通過writeToParcel(),使用一個Parcel物件將中間結果儲存起來,而接收端程序則會使用CREATOR物件把作為Parcel物件的中間物件再恢復出來,通過類的初始化方法以這個Parcel物件為基礎來建立新物件。後續的4-6,則是完成這個CREATOR物件的實現。
4、createFromParcel(),這是ParcelableCreator<T>模板類所必須實現的介面方法,提供從Parcel轉義出新的物件的能力。接收端來接收傳輸過來的Parcel物件時,便會以這一個介面方法來取得物件。我們這裡直接呼叫基於Parcel 的類的初始化方法,然後將建立的物件返回。
5、newArray(),這是ParcelableCreator<T>模板類所必須實現的另一個介面方法,但這一方法用於建立多個這種實現了Parcelable介面的類。通過這一方法,CREATOR物件不光能建立單個物件,也能返回多個建立好的空物件,但多個物件不能以某個Parcel物件為基礎建立,於是會使用預設的類創始化方法。
6、實現具體的以Parcel為參照的初始化方法,這並非必須,我們也可以在createFromParcel()裡直接根據Parcel的值賦值到物件來實現,但這樣實現則更清晰。這一方法,基本上與writeToParcel()是成對的,以什麼順序將物件屬性寫入Parcel,則在createFromParcel()會就會以同樣的順序物件屬性從Parcel裡讀出來,使用Parcel的readInt()、readLong()等方法來完成。

7.應用例項

就應用程式而言,最常見使用Parcel類的場景就是在Activity間傳遞資料。沒錯,在Activity間使用Intent傳遞資料的時候,可以通過Parcelable機制傳遞複雜的物件。

 在下面的程式中,MyColor用於儲存一個顏色值,MainActivity在使用者點選螢幕時將MyColor物件設成紅色,傳遞到SubActivity中,此時SubActivity的TextView顯示為紅色的背景;當點選SubActivity時,將顏色值改為綠色,返回MainActivity,期望的是MainActivity的TextView顯示綠色背景。
MyColor類的實現程式碼:

package com.test;

import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;

public class MyColor implements Parcelable {
	private int color=Color.BLACK;
	
	MyColor(){
		color=Color.BLACK;
	}
	
	MyColor(Parcel in){
		color=in.readInt();
	}
	
	public int getColor(){
		return color;
	}
	
	public void setColor(int color){
		this.color=color;
	}
	
	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(color);
	}

    public static final Parcelable.Creator<MyColor> CREATOR
	    = new Parcelable.Creator<MyColor>() {
		public MyColor createFromParcel(Parcel in) {
		    return new MyColor(in);
		}
		
		public MyColor[] newArray(int size) {
		    return new MyColor[size];
		}
	};
}

MainActivity的程式碼:
package com.test;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;


public class MainActivity extends Activity {
    private final int SUB_ACTIVITY=0;
    private MyColor color=new MyColor();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode==SUB_ACTIVITY){
			if (resultCode==RESULT_OK){
	        	if (data.hasExtra("MyColor")){
	        		color=data.getParcelableExtra("MyColor");  //<span style="font-size: 14px; white-space: pre;">反序列化後是一個新的MyColor物件</span>
	        		findViewById(R.id.text).setBackgroundColor(color.getColor());
	        	}
			}
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event){
		if (event.getAction()==MotionEvent.ACTION_UP){
			Intent intent=new Intent();
			intent.setClass(this, SubActivity.class);
			color.setColor(Color.RED);
			intent.putExtra("MyColor", color);
			startActivityForResult(intent,SUB_ACTIVITY);	
		}
		return super.onTouchEvent(event);
	}

}

SubActivity的程式碼:
package com.test;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.TextView;

public class SubActivity extends Activity {
	private MyColor color;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((TextView)findViewById(R.id.text)).setText("SubActivity");
        Intent intent=getIntent();
        if (intent!=null){
        	if (intent.hasExtra("MyColor")){
        		color=intent.getParcelableExtra("MyColor");
        		findViewById(R.id.text).setBackgroundColor(color.getColor());
        	}
        }
    }
    
	@Override
	public boolean onTouchEvent(MotionEvent event){
		if (event.getAction()==MotionEvent.ACTION_UP){
			Intent intent=new Intent();
			if (color!=null){
				color.setColor(Color.GREEN);
				intent.putExtra("MyColor", color);
			}
			setResult(RESULT_OK,intent);
			finish();
		}
		return super.onTouchEvent(event);
	}
}

在MainActivity的onActivityResult()中,有一句color=data.getParcelableExtra("MyColor"),這說明的是反序列化後是一個新的MyColor物件,因此要想使用這個物件,我們做了這個賦值語句。

如果資料本身是IBinder型別,那麼反序列化的結果就是原物件,而不是新建的物件,很顯然,如果是這樣的話,在反序列化後在MainActivity中就不再需要color=data.getParcelableExtra("MyColor")這句了。因此,換一種MyColor的實現方法,令其中的int color成員變數使用IBinder型別的成員變數來表示。

新建一個BinderData類繼承自Binder,程式碼如下:

package com.test;

import android.os.Binder;

public class BinderData extends Binder {
	public int color;
}

修改MyColor的程式碼如下:
 package com.test;

import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;

public class MyColor implements Parcelable {
	private BinderData data=new BinderData();
	
	MyColor(){
		data.color=Color.BLACK;
	}
	
	MyColor(Parcel in){
		data=(BinderData) in.readValue(BinderData.class.getClassLoader());
	}
	
	public int getColor(){
		return data.color;
	}
	
	public void setColor(int color){
		data.color=color;
	}
	
	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeValue(data);
	}

    public static final Parcelable.Creator<MyColor> CREATOR
	    = new Parcelable.Creator<MyColor>() {
		public MyColor createFromParcel(Parcel in) {
		    return new MyColor(in);
		}
		
		public MyColor[] newArray(int size) {
		    return new MyColor[size];
		}
	};
}

去掉MainActivity的onActivityResult()中的color=data.getParcelableExtra("MyColor")一句,變成:
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode==SUB_ACTIVITY){
			if (resultCode==RESULT_OK){
	        	if (data.hasExtra("MyColor")){
	        		findViewById(R.id.text).setBackgroundColor(color.getColor());
	        	}
			}
		}
	}


相關推薦

Android序列機制——ParcelParcelable

當我們在呼叫遠端方法時,需要在程序間傳遞引數以及返回結果。這種類似的處理方式,需要把資料與程序相關性去除,變成一種中間形式,然後按統一的介面進行讀寫操作。這樣的機制,一般在高階程式語言裡都被稱為序列化。 在Android世界裡處理資料的序列化操作的,使用了一種Parcel

Android序列序列

這幾天在看到設計模式時,看到有關於序列化的知識,發現自己之前這塊知識很欠缺,所以這花了兩天仔細研究了一下,感覺這個東西還是很有趣的(當然也很有用-。+),今天給大家帶來這篇文章,希望對大家有幫助。序列化概念和應用首先我們需要知道序列化是個什麼意思。序列化:將物件轉換為可傳輸的

java序列序列的問題

java序列化是將java物件轉換為位元組序列的過程,變成計算機能夠儲存的二進位制序列       反序列化是將位元組序列恢復成java物件的過程 1.當兩個Java程序進行通訊時,能否實現程序間的物件傳送呢?答案是可以的。如何做到呢?這就需要Java序列化與反

java可定製的序列過程 writeObjectreadObject

在Java中使用Serialization相當簡單。如果你有一些物件想要進行序列化,你只需實現Serializable介面。然後,你可以使用ObjectOutputStream將該物件儲存至檔案或傳送到其他主機。所有的non-transient和non-static欄位都將被序列化,並且由反序列化重構造出一

java序列序列

       把物件轉換為位元組序列的過程稱為物件的序列化。   把位元組序列恢復為物件的過程稱為物件的反序列化。   物件的序列化主要有兩種用途:   1) 把物件的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中;   2) 在網路上傳送物件的位元組序列

return,抽象類介面,物件序列機制,this和super,識別符號,break和continue以及return,final,finally和finalize

               (2)介面中定義的成員變數預設為public static final,只能夠有靜態的不能被修改的資料成員,而且,必須給其賦初值,其所有的成員變數只能被public,abstract這兩個關鍵字修飾。抽象類可以有自己的成員變數,還可以有非抽象的成員方法,抽象類的成員變數預設為de

詳解Android回撥機制RecyclerView的Item點選事件實現

總是看書上寫著回調回調,以為就是函式呼叫換了個名字,尤其是看了Button的點選事件實現後,覺得不就是觸發機制。 A事件發生->後臺處理邏輯->告訴前臺怎麼做->結束。 Android常見button點選事件: loginB

Android序列 Serializable使用和Parcelable 外掛使用 以及兩者區別

當activity之間需要傳輸自定義的實體類物件時,就需要將資料序列化。有兩種方式可以實現:實現Serializable介面 和 實現Parcelable介面 Serializable: 是java提供的一個序列化介面,是個空介面,為物件提供標準的

Android 進階6:兩種序列方式 Serializable 和 Parcelable

什麼是序列化 我們總是說著或者聽說著“序列化”,它的定義是什麼呢? 序列化 (Serialization)將物件的狀態資訊轉換為可以儲存或傳輸的形式的過程。在序列化期間,物件將其當前狀態寫入到臨時或永續性儲存區。以後,可以通過從儲存區中讀取或反序列化物

Android物件序列(Activity之間傳遞物件,Parcelable小例子)

Android中為了能夠在Activity之間傳遞值,需要只用Intent中的put函式。 其中bundle.putParcelable可以實現傳遞物件,但是這個物件的類必須實現Parcelable接口才能夠使用。 下面是一個簡單的在Activity之間傳遞物件的例子

Parcelable序列傳送資料技巧

前言 Android開發中在activity之間傳輸資料應該是經常碰到的,如整數,字串等等。但是假如我們要傳輸一個類呢? 簡單的講就是把資料放到共享記憶體中,這樣其他多個程序就都可以從這個記憶體中訪問。 可能有人說為什麼不用Serializable進行序列化?一個字

Android 的快取機制實現

public class NewsListActivity extends Activity { private List<News> list; private ListView listView; private LoadImageAdapter adapter;//介面卡

Java 序列序列

一、 序列化和反序列化概念 Serialization(序列化)是一種將物件以一連串的位元組描述的過程;反序列化deserialization是一種將這些位元組重建成一個物件的過程。將程式中的物件,放入檔案中儲存就是序列化,將檔案中的位元組碼重新轉成物件就是反序列化。 二、 序列化和反序列化的必要性 當兩個程

在.net序列讀寫xml方法的總結

port 單詞 創建 padding 在一起 sys base msd 屏幕 在.net中序列化讀寫xml方法的總結 閱讀目錄 開始 最簡單的使用XML的方法 類型定義與XML結構的映射 使用 XmlElement 使用 XmlAttribute 使用 Inner

Android對Handle機制的理解

trac 意義 還要 break create findview curl net protected 一、重要參考資料 【參考資料】 眼下來看,以下的幾個網址中的內容質量比較不錯。基本不須要再讀別的網址了。 1、android消息機制一

Unity序列和反序列

private ons 並且 行修改 ges 面向對象 我們 為我 -1 為了滿足面向對象中的封裝性,我們通常使用private關鍵字使變量私有化,讓外界無法訪問修改,起到保護作用。 但是一些特殊情況,我們希望在Unity中Inspector面板中修改到腳本組件中的私有成員

序列之Java默認序列技術(ObjectOutputStreamObjectInputStream)

object java outputstream Java默認序列化技術 主要是通過對象輸出流java.io.ObjectOutputStream對象輸入流java.io.ObjectInputStream來實現的 package com.xingej.ser; public

Android內存泄露如何有效避免OOM總結

ignore create ui線程 nbsp weak solver 部分 ont 占用 一、關於OOM與內存泄露的概念 我們在Android開發過程中經常會遇到OOM的錯誤,這是因為我們在APP中沒有考慮dalvik虛擬機內存消耗的問題。 1

Android組件框架設計實踐

交叉 string 構建 即使 插入 開始 build 很多 www 在目前移動互聯網時代,每個 APP 就是流量入口,與過去 PC Web 瀏覽器時代不同的是,APP 的體驗與叠代速度影響著用戶的粘性,這同時也對從事移動開發人員提出更高要求,進而移動端框架也層出不窮。

Java簡單模擬AndroidHandler-Message機制

就是 示例代碼 pri 技術分享 android ble [] handle @override 在Android中主線程與子線程的通信十分重要,Google工程師為我們提供了Handler-Message機制來解決他們之間的交互問題。今天,我們就來簡單理解Handler-