Kotlin - 實現Android中的Parcelable
使用 Parcelable 的最基本用例是當我們需要將模型從一個活動傳遞到另一個活動時。當傳遞原始類型時,很簡單,但是當我們想要傳遞自己的對象時,我們需要對它們做一些事情:
如果我們認為我們使用的 Person 對象與上一篇文章相同,則會在第11行收到編譯錯誤,因為我們無法照原樣傳遞 Person 模型。
我們的模型不符合以上任何條件,因此我們需要對此做些事情,我們有一些選擇:
因此,Parcelable是最好的選擇,但是不幸的是,它涉及很多樣板代碼,每次我們對模型進行更改時,我們所有人都必須編寫和更新這些樣板代碼。在Java中,如果我們使用AutoValue,就可以避免編寫和維護所有樣板代碼,但是在Kotlin中呢?
接下來,讓我們使用上一篇文章中的Person模型,看看如何在Kotlin中實現Parcelable。如果您還記得,這就是現在的樣子,只有一行代碼。
目前這是一項實驗性功能,因此我們需要將以下代碼段添加到我們的應用程序build.gradle文件中:
太好了吧?沒有更多的可打包樣板代碼。Parcelable實現所需的所有代碼都是由註釋處理器生成的,我們根本不必擔心,也不必首先編寫它,也不必在每次更改模型時進行維護和更新。
遠離28行代碼,回到簡潔易讀的模型。如果您忽略了我為使要點看起來不錯而在這裡執行的換行符,則可以輕鬆地將其包含在兩行代碼中,其中一行用於註釋,另一行用於類定義。
Kotlin再次做了出色的工作,幫助我們擺脫了不必要的樣板代碼。我每天都越來越愛這種語言,您是否有同感?:)
不過,Parcelize仍然存在一個小問題。目前,Android Studio出現問題,顯示有關Parcelable接口的不完整實現的錯誤:
這是IDE本身中的一個已知錯誤,您可以忽略它,代碼沒有錯,並且可以按預期工作。您可以在此處跟踪問題。目前處於In Progress狀態。
注意:AndroidDeveloperLB 在文章的第一條評論中提到了Parcelize的另外兩個問題。其中一個僅影響1.1.4版,另一個也影響1.1.5版。請確保更新到可用的最新Kotlin版本,以免出現這些情況。第一個有點極端情況,因為如果您嘗試在Parcelable中使用Serializable對象並且不確定為什麼我會這樣做,則會發生這種情況。
第二個可能更重要,因為它實際上阻止您在運行Android 4.4以下版本的設備上安裝該應用程序,而這實際上更為常見。
class ActivityA : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, ActivityB::class.java)
val person = Person("name", 32, "email@email.com", 1234)
intent.putExtra("A_STRING", "some string")
intent.putExtra("A_NUMBER", 1234)
intent.putExtra("AN_OBJECT", person) // compilation error
startActivity(intent)
}
}
如果我們認為我們使用的 Person 對象與上一篇文章相同,則會在第11行收到編譯錯誤,因為我們無法照原樣傳遞 Person 模型。
我們的模型不符合以上任何條件,因此我們需要對此做些事情,我們有一些選擇:
- Implement Serializable:希望您不再這樣做,儘管它有效且易於實施,但由於它基於反射,因此性能相當差。
- Json String representation:您也可以這樣做,並將模型作為String傳遞。同樣,這也非常簡單,特別是如果您已經Gson在項目中使用了類似功能,但又不是最佳選擇。
- Implement Parcelable:這顯然是正確的答案。根據官方文檔,這是推薦的方式。它也適用於 marshalling/unmarshallingJava 對象,例如序列化,但性能更高。
因此,Parcelable是最好的選擇,但是不幸的是,它涉及很多樣板代碼,每次我們對模型進行更改時,我們所有人都必須編寫和更新這些樣板代碼。在Java中,如果我們使用AutoValue,就可以避免編寫和維護所有樣板代碼,但是在Kotlin中呢?
接下來,讓我們使用上一篇文章中的Person模型,看看如何在Kotlin中實現Parcelable。如果您還記得,這就是現在的樣子,只有一行代碼。
data class Person(val name: String, val age: Int, val email: String, val phone: Long)
標準方式
首先,讓我們採用標準方法,看看它在Kotlin中的外觀。因此,如果我們使Person模型實現Parcelable接口並要求Android Studio寫下所有必需的代碼,那麼我們將得到:data class Person(val name: String, val age: Int, val email: String, val phone: Long) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt(),
parcel.readString(),
parcel.readLong())
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
parcel.writeString(email)
parcel.writeLong(phone)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Person> {
override fun createFromParcel(parcel: Parcel): Person {
return Person(parcel)
}
override fun newArray(size: Int): Array<Person?> {
return arrayOfNulls(size)
}
}
}
如前所述,其中涉及很多樣板代碼。我們可以通過使用Android Studio生成模板來避免最初編寫它,但是我們仍然必須維護它。對於這麼小的模型,我們從1行代碼增加到28行。在更現實的示例中,當我們需要添加屬性時,會發生什麼?例如,如果要向Person模型添加address屬性,則需要至少更新constructor和writeToParcel方法並添加新字段,以便我們的模型仍符合Parcelable實現。Parcelize
打包救助來了。JetBrains在Kotlin 1.1.4版本中引入了它,這是什麼?在他們的話:自動 打包實現生成器。在主要構造函數中聲明序列化的屬性,並添加一個 @Parcelize 註釋,以及 writeToParcel()/createFromParcel() 方法將自動創建
目前這是一項實驗性功能,因此我們需要將以下代碼段添加到我們的應用程序build.gradle文件中:
androidExtensions {
experimental = true
}
這是我們的模型現在的樣子:
@Parcelize
data class PersonParcelize(val name: String,
val age: Int,
val email: String,
val phone: Long) : Parcelable
太好了吧?沒有更多的可打包樣板代碼。Parcelable實現所需的所有代碼都是由註釋處理器生成的,我們根本不必擔心,也不必首先編寫它,也不必在每次更改模型時進行維護和更新。
遠離28行代碼,回到簡潔易讀的模型。如果您忽略了我為使要點看起來不錯而在這裡執行的換行符,則可以輕鬆地將其包含在兩行代碼中,其中一行用於註釋,另一行用於類定義。
不過,Parcelize仍然存在一個小問題。目前,Android Studio出現問題,顯示有關Parcelable接口的不完整實現的錯誤:
留言
張貼留言