嗨偷厦,大家好库糠,歡迎來到系列文章的第五篇司忱,在這里我們將研究在Kotlin中處理Parcelable對象北秽。前面文章我們研究了data class這里我們將data class繼承Parcelable接口蜡峰。
使用Parcelable最常見的場景是將一個數(shù)據(jù)模型從一個Activity傳遞給另外一個Activity了袁。當(dāng)傳遞基本數(shù)據(jù)類型沒什么問題,但是要傳遞自定義的對象粥诫,那么我們需要做一些操作:
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類和上篇文章的Person一樣保持不變的話,那么上面代碼的第11行會報編譯錯誤执赡,因為我們不能這樣傳遞Person模型沙合。我們的Person類模型不符合上面的任何一條,我們有一些選擇可以做:
實現(xiàn)Serializable: 希望你不要再這樣做究履,雖然簡單高效最仑,但是性能卻很差肥惭,因為它基于反射蜜葱。
Json String representation: 你也可以將模型轉(zhuǎn)換為String后再傳遞牵囤。這樣做也很簡單揭鳞,特別是當(dāng)你使用了類似Gson這樣的庫的時候野崇,但這仍然不是最優(yōu)方案乓梨。
實現(xiàn)Parcelable: 這是正確答案扶镀。這是官方推薦的解決方案昆雀。和serialization一樣狞膘,它也能編組/解組(marshalling/unmarshalling)Java對象客冈,但是更加高效场仲。
Parcelable是最好的方案但是它包含很多模板代碼渠缕,因此每次更細數(shù)據(jù)模型的時候我們都要編寫和更新代碼亦鳞。在Java中我們可以使用AutoValue來避免模板代碼燕差,但是Kotlin呢徒探?
下面我們看下怎樣將前篇文章中的Person類實現(xiàn)Parcelable测暗,一行代碼的Person類:
data class Person(val name: String, val age: Int, val email: String, val phone: Long)
標(biāo)準(zhǔn)方法
首先我們使用傳統(tǒng)的標(biāo)準(zhǔn)方法碗啄。讓Person類繼承Parcelable接口并按照Android Studio的要求實現(xiàn)相關(guān)API:
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)
}
}
}
可以看到上面的代碼包含很多模板代碼(boilerplate code),這不是我們希望看到的褒傅。我們可以通過使用Android Studio來生成模板代碼來避免編寫它殿托,但是我們?nèi)匀恍枰S護它支竹。只是繼承了Parcelable礼搁,我們的Person類就從1行代碼變成了28行代碼馒吴。如果在實際項目中這樣做饮戳,不知道會有什么后果扯罐。如果我們給Person新加個address的屬性,那么我們至少要更改構(gòu)造器和writeToParcel這兩個方法秸歧。有沒有感覺很累键菱?累就對了纱耻。
利用Parcelize
Parcelize來拯救你了。JetBrains在Kotlin 1.1.4 release版本中引入了它,那有怎么樣贬派?官方的說法是:
An automatic Parcelable implementation generator. Declare the serialized properties in a primary constructor and add a
@Parcelize
annotation, andwriteToParcel()
/createFromParcel()
methods will be created automatically
目前為止波桩,它和Kotlin Coroutine一樣也是實驗性的特性,若要使用的話需要在app模塊的build.gradle文件中添加下面代碼:
androidExtensions {
experimental = true
}
然后我們的Person代碼如下:
@Parcelize
data class PersonParcelize(val name: String,
val age: Int,
val email: String,
val phone: Long) : Parcelable
驚訝嗎萤皂?沒有任何Parcelable的模板代碼了。所有Parcelable的實現(xiàn)都會通過注解處理器處理而我們不需要關(guān)心它們入录,也不需要編寫它們,更改數(shù)據(jù)模型的時候也不需要更改太多代碼。
去掉了28行代碼唤崭,得到一個簡潔且易于閱讀的模型。換行符只是為了讓代碼看起來更好,你可以忽略換行符酸茴,你可以很容易地將它分為兩行代碼,一個用于注釋酪穿,另一個用于類定義救赐。
Kotlin再一次做了一件了不起的工作,幫助我們擺脫了不必要的樣板代碼。我越來越喜歡這門語言了配乓,你有同感嗎?:)
盡管如此,關(guān)于Parcelize還有一個小問題蜈膨。目前驴一,Android Studio出現(xiàn)了一個問題,它顯示了一個不完整的Parcelable接口實現(xiàn)的錯誤:這是IDE本身的一個已知的bug灶壶,你可以忽略它而可以正常運行肝断。你可以跟蹤這個問題。目前它處于“開發(fā)”狀態(tài)驰凛。
注意: 在本文評論的第一條中胸懈,AndroidDeveloperLB提到了兩個問題。第一個問題只存在1.1.4版本中恰响,第二個問題還存在1.1.5版本趣钱。請使用最新的kotlin版本來避免這樣的問題。第一個問題出現(xiàn)的情況比較少渔隶,當(dāng)你在Parcelable中使用Serializable對象的時候會觸發(fā)第一個問題羔挡,但是我不清楚我為什么要這樣做。
第二個問題似乎更加嚴(yán)重和常見间唉,因為apk無法安裝到Andorid 4.4以下的設(shè)備绞灼。
好了,所有的parcels已經(jīng)講完 :)呈野。如果你喜歡本文給一些 ??或者分享你的想法和評論低矮。代碼在這里:Series Github project,在parcelize包下被冒。See you at number 6 ??
翻譯自Parcelable in Kotlin? Here comes Parcelize军掂。翻譯不好或者錯誤的地方請留言。