摘要:而且這種方式也是推薦的序列化方式,因此我們應該首選。只要實現了這個接口,一個類的對象就可以實現序列化并可以通過和進行傳遞了。
文章參考自任玉剛大神的書籍《Android開發藝術探索》,強烈推薦這本書。
在進行Android開發的時候我們有時候需要用到數據的持久化存儲,或者在進程之間傳遞數據。其中就可能需要用到對象的序列化,經過序列化的對象之后可以通過Intent或者Boundle來傳輸了。接下來還是想些介紹下吧。
1.什么叫序列化,什么叫反序列化序列化: 將數據結構或對象轉換成二進制串的過程。
反序列化:將在序列化過程中所生成的二進制串轉換成數據結構或者對象的過程。
簡單來說,序列化就是將我們生成的對象進行存儲起來(比如磁盤上),以用來將來使用或者在網絡上進行傳輸,而反序列化呢,就是由我們的之前序列化生成的二進制串重新生成對象的過程。注意,這里我們反復說的序列化啦,反序列化啦,都是針對的對象,而非類。因為我們是針對對象進行存取與傳輸的,而非類,當我們需要重新獲取之前的對象的時候,是直接讀取出來的(從文件或網絡中),而非根據類new出一個對象,這點是需要注意的。
2.如何序列化序列話的方式有兩種,一種是實現Serializable接口,一種是實現Parceable接口,下面會具體介紹這兩種方式。
a.實現Serializable接口這種序列化方式是Java提供的,它的優點是簡單,其實Serializable接口是個空接口,因而我們并不需要實現什么抽象方法,但是我們卻往往需要在類中聲明一個靜態變量標識(serialVersionUID),但這不是必須的,我們不聲明,依然可以實現序列化,但是這樣的話會對反序列化產生一定的影響,可能會在我們對類做了修改之后而造成對象的反序列化失敗。聲明方式如下:
private static final long serialVersionUID = 8711368828010083044L;
注意,這里的值可以是任意值。
下面我們來具體實現下。
package com.qc.admin.myserializableparceabledemo; import java.io.Serializable; /** * Created by admin on 2016/12/1. */ public class User implements Serializable { private static final long serialVersionUID = 519067123721295773L; public int userId; public String userName; public boolean isMale; public User(int userId, String userName, boolean isMale) { this.userId = userId; this.userName = userName; this.isMale = isMale; } @Override public String toString() { return "User{ " + "userId = " + userId + ", userName = " + userName + ", isMale = " + isMale + " }"; } }
下面是序列化與反序列化過程:
private void beginSerizable() throws IOException, ClassNotFoundException { // 序列化 User user = new User(2016, "qian", true); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getFilesDir(), "myfile.txt"))); out.writeObject(user); out.close(); // 反序列化 // 注意,這里后面的“/myfile.txt”前面有個斜杠“/”,否則會報“FileNotFoundException”異常 ObjectInputStream in = new ObjectInputStream(new FileInputStream(getFilesDir() + "/myfile.txt")); User mUser = (User) in.readObject(); textView.setText(mUser.toString()); in.close(); Log.i("test",mUser.toString()); }
運行結果截圖:
注意:如果是在Android項目中調用以上方法,別忘了在Manifest.xml文件中配置如下權限:
b.實現Parceable接口
這種方式是Android提供的方式,相比較前面那種方式來講,這種方式稍微有點復雜,我們需要自己盡享序列化與反序列化的操作,但是它卻更加高效,并不需要執行大量的I/O操作。而且這種方式也是Android推薦的序列化方式,因此我們應該首選Parceable。只要實現了這個接口,一個類的對象就可以實現序列化并可以通過Intent和Binder進行傳遞了。下面請看實例:
public class Book implements Parcelable { public String bookTitle; public int bookId; protected Book(Parcel in) { bookTitle = in.readString(); bookId = in.readInt(); } public static final CreatorCREATOR = new Creator () { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(bookTitle); parcel.writeInt(bookId); } }
這里將Book這個類就實現了Parcelable接口,其實在Android Studio IDE中,上述過程很簡單,我們只需要定義一個類,實現Parcelable接口,然后在里面定義我們的屬性或者說是字段,根據提示的錯誤,按照它提示的方法覆蓋相應的方法,之后的一切其實都可以自動生成(不過如果需要構造方法的話,那就需要自動生成了,toString()方法也是自己實現的),所以不用擔心在Android開發中通過實現Parceable接口會比較麻煩,因為AS都會為你自動生成。
上面我們已經完整的將Book類實現了Parceable接口,那接下來如何序列化和反序列化呢?如果你說,剛才不是已經說過了嗎,采用文件讀取的方式不久可以了啦...當你那樣做的時候,你會發現會報如下的錯誤:
Why???...什么情況?提示我們Book類沒有實現序列化:
/System.err: java.io.NotSerializableException: com.qc.admin.myserializableparceabledemo.Book
好啦,之所以出現這種問題,并不是我們的實現過程有問題,而是使用該類的方式行不通。到這里我們就明白了Serializable和Parceable兩種方式實現序列化還是有區別的,剛才我們也講了,Parceable更加高效,不會像Serializable那樣有大量的I/O操作,這句話的具體含義就道出了Serializable與Parcelable區別:雖然兩者都是用于支持序列化、反序列化話操作,但是兩者最大的區別在于存儲媒介的不同,Serializable是將序列化后的對象存儲在硬盤上,使用I/O讀寫的方式,而Parcelable是將其存儲在內存中,是針對內存的讀寫,熟悉計算機組成原理的朋友都知道,內存的讀寫速度顯然要遠遠大于I/O的讀寫速度,這也是為什么Android中推薦使用Parcelable這種方式來實現對象的序列化。
那我們應該怎么使用通過實現Parcelable接口實現序列化的對象呢?答案是:通過Intent方式傳遞,除了基本類型外,Intent只能傳輸序列化之后的對象,對應這兩種序列化方式,也有兩種相應的方法:
mIntent.getSerializableExtra(string name );
mIntent.getParcelableExtra(String name );
當然,放入的操作就沒有這種區分了,都是方法:
mIntent.putExtra();
我們可以在第一個Activity中將序列化對象放入Intent,在另一個Activity中取出,比如:
在另一端獲取對象,例如:
Bundle mBundle = getIntent().getExtras(); Book mBook = mBundle.getParcelable("book1");
下面再看類User實現Parceable接口的過程,它內部包含了一個可序列化的類Book,具體細節跟上面的有點不同:
package com.qc.admin.myserializableparceabledemo; import android.os.Parcel; import android.os.Parcelable; /** * Created by admin on 2016/12/1. */ public class User implements Parcelable { public int userId; public String userName; public boolean isMale; public Book book; public User(int userId, String userName, boolean isMale, Book book) { this.userId = userId; this.userName = userName; this.isMale = isMale; this.book = book; } protected User(Parcel in) { userId = in.readInt(); userName = in.readString(); isMale = in.readByte() != 0; // 此為不同之處1 // 也可以通過這種方式:book = in.readParcelable(Thread.currentThread().getContextClassLoader()); book = in.readParcelable(Book.class.getClassLoader()); } public static final CreatorCREATOR = new Creator () { @Override public User createFromParcel(Parcel in) { return new User(in); } @Override public User[] newArray(int size) { return new User[size]; } }; // 幾乎在所有的情況下都應該返回0,只有在當前對象中存在文件描述的時候,此方法返回CONTENTS_FILE_DESCRIPTOR(常量值為1) @Override public int describeContents() { return 0; } // 將對象寫入序列化結構中,其中i標識有兩種值,0或者1(PARCELABLE_WRITE_RETURN_VALUE) // 為1時表示當前對象需要作為返回值返回,不能立即釋放資源,幾乎所有情況都為0 @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(userId); parcel.writeString(userName); // 注意這里,并不是直接寫入boolean值,而是寫入整數值 parcel.writeByte((byte) (isMale ? 1 : 0)); // 此為不同之處2 parcel.writeParcelable(book, i); } @Override public String toString() { return "User{ " + "userId = " + userId + ", userName = " + userName + ", isMale = " + isMale + "book = " + book.toString() + " }"; } }
可以看出,結果已經正確的打印了出來了:
注意:在 Parcelable 中,我們無法直接寫入 boolean 值,而是將其轉化為整數值進行保存,這里為 Byte,當然,你也可以使用 Int 等。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66307.html
摘要:靜態變量序列化情境查看清單的代碼。之所以打印的原因在于序列化時,并不保存靜態變量,這其實比較容易理解,序列化保存的是對象的狀態,靜態變量屬于類的狀態,因此序列化并不保存靜態變量。解決要想將父類對象也序列化,就需要讓父類也實現接口。 原文 https://www.ibm.com/developer... 引言 將 Java 對象序列化為二進制文件的 Java 序列化技術是 Java 系...
摘要:的序列化是將一個對象表示成字節序列,該字節序列包括了對象的數據,有關對象的類型信息和存儲在對象中的數據類型。這個是根據類名接口名成員方法及屬性等來生成一個位的哈希字段,因為增加了字段,因此生成的不一樣了。 Java序列化 什么是序列化? 序列化是將一個對象的狀態,各屬性的值序列化保存起來,然后在合適的時候通過反序列化獲得。 Java的序列化是將一個對象表示成字節序列,該字節序列包括了對...
閱讀 1211·2023-04-25 20:31
閱讀 3718·2021-10-14 09:42
閱讀 1485·2021-09-22 16:06
閱讀 2636·2021-09-10 10:50
閱讀 3524·2021-09-07 10:19
閱讀 1772·2019-08-30 15:53
閱讀 1170·2019-08-29 15:13
閱讀 2818·2019-08-29 13:20