Android通過(guò)Intent傳遞自定義對(duì)象的兩種方式
前言
我們經(jīng)常會(huì)使用 Intent 來(lái)啟動(dòng) Activity、發(fā)送廣播等。在進(jìn)行上述操作的過(guò)程中,我們還可以往 Intent 對(duì)象中添加額外的數(shù)據(jù),比如:
// MainActivity.kt
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("name", "Martin")
intent.putExtra("age", 21)
startActivity(intent)
以此來(lái)完成數(shù)據(jù)的傳遞:
// AnotherActivity.kt
val name = intent.getStringExtra("name") ?: "Unknown Name"
val age = intent.getIntExtra("age", -1)
但問(wèn)題在于 putExtra 可傳遞的數(shù)據(jù)類型是有限的,如果你想傳遞自定義對(duì)象,就行不通了。但請(qǐng)別擔(dān)心,我們接下來(lái)就來(lái)學(xué)習(xí)如何通過(guò) Intent 傳遞自定義對(duì)象。
方式一:Serializable
Serializable 翻譯過(guò)來(lái)是序列化的意思,表示將一個(gè)對(duì)象轉(zhuǎn)換為可存儲(chǔ)或可傳輸?shù)臓顟B(tài),序列化后的對(duì)象可被存儲(chǔ)到本地,也可在網(wǎng)絡(luò)上進(jìn)行傳輸。
序列化一個(gè)類,其實(shí)非常簡(jiǎn)單,只需讓這個(gè)類實(shí)現(xiàn) Serializable 接口即可。例如:
class Person : Serializable {
var name = ""
var age = 0
}
這樣,所有的 Person 對(duì)象都是可序列化的了?,F(xiàn)在,我們想要傳遞一個(gè) Person 對(duì)象,只需這樣:
val person = Person()
person.name = "Jack"
person.age = 21
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("person", person)
startActivity(intent)
那么,該怎么從 Intent 中取出這個(gè) Person 對(duì)象呢?
答案是使用 getSerializableExtra() 方法獲取序列化對(duì)象,再向下轉(zhuǎn)型為 Person 對(duì)象即可。
// val person_from_intent: Person = intent.getSerializableExtra("person") as Person
不過(guò),這個(gè)方法已經(jīng)被廢棄了。原因在于它不能保證類型安全,如果獲取到的不是 Person 類型的對(duì)象,又或是鍵名拼寫(xiě)錯(cuò)誤導(dǎo)致返回 null,那么在運(yùn)行時(shí),as 強(qiáng)制類型轉(zhuǎn)換可能會(huì)失敗并導(dǎo)致程序崩潰。
所以,現(xiàn)在我們會(huì)使用更安全的重載方法 getSerializableExtra(String, Class<T>)。這個(gè)方法是在 Android 13 (API 33) 引入的,為了兼容所有版本,我們需要這樣寫(xiě):
val person: Person? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getSerializableExtra("person", Person::class.java)
} else {
// 使用 as? 安全轉(zhuǎn)型來(lái)避免崩潰
@Suppress("DEPRECATION")
intent.getSerializableExtra("person") as? Person
}
這樣,我們就成功實(shí)現(xiàn)了通過(guò) Intent 來(lái)傳遞自定義對(duì)象。
最后注意一點(diǎn):在這個(gè)過(guò)程中,會(huì)將對(duì)象序列化為可存儲(chǔ)或可傳輸?shù)臓顟B(tài),再將其反序列化為一個(gè)新的對(duì)象。雖然這兩個(gè)對(duì)象存儲(chǔ)的數(shù)據(jù)一致,但其實(shí)是兩個(gè)不相同的對(duì)象。
方式二:Parcelable
我們也可以通過(guò) Parcelable 來(lái)完成。只不過(guò)它的實(shí)現(xiàn)原理是將完整的對(duì)象進(jìn)行分解,使得分解后的每一個(gè)部分都是 Intent 所支持的數(shù)據(jù)類型,這樣也能實(shí)現(xiàn)通過(guò) Intent 來(lái)傳遞自定義對(duì)象的功能。
如果使用 Parcelable 的實(shí)現(xiàn)方式,Person 類的代碼將會(huì)是這樣的:
class Person(var name: String?, var age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
// 將當(dāng)前類中的字段寫(xiě)出
parcel.writeString(name)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
// 注意:讀取字段的順序需要和寫(xiě)出字段的順序保持一致。
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)
}
}
}
可以看到,手動(dòng)編寫(xiě)這些模版代碼非常繁瑣。為此,Kotlin 提供了一種更加簡(jiǎn)便的用法。
我們先在 app/build.gradle.kts 文件中添加插件依賴:
plugins {
id("kotlin-parcelize")
}
然后,修改 Person 類:
import kotlinx.parcelize.Parcelize @Parcelize data class Person(var name: String, var age: Int) : Parcelable
只需加上一個(gè) @Parcelize 注解,就可以省去了一大堆模板代碼的麻煩。
注意:使用 @Parcelize 時(shí),所有要傳遞的數(shù)據(jù)都必須在類的主構(gòu)造函數(shù)中聲明。
接下來(lái),在獲取 Intent 中的數(shù)據(jù)時(shí),只需使用 getParcelableExtra() 方法即可。同樣地,需要處理版本兼容問(wèn)題:
val person: Person? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra("person", Person::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra<Person>("person")
}
對(duì)比
對(duì)比 Serializable 和 Parcelable 這兩種方式,Serializable 的實(shí)現(xiàn)非常簡(jiǎn)單,但它序列化時(shí)會(huì)用到反射,導(dǎo)致性能開(kāi)銷大。Parcelable 則通過(guò)顯式的讀寫(xiě)操作來(lái)分解對(duì)象,沒(méi)有反射的開(kāi)銷,效率要高得多。
因此,在安卓開(kāi)發(fā)中,通常情況下,我們都會(huì)選擇使用 Parcelable 的方式。
以上就是Android通過(guò)Intent傳遞自定義對(duì)象的兩種方式的詳細(xì)內(nèi)容,更多關(guān)于Android Intent傳遞自定義對(duì)象的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android Toast實(shí)現(xiàn)全屏顯示
這篇文章主要為大家詳細(xì)介紹了Android Toast實(shí)現(xiàn)全屏顯示,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android利用動(dòng)畫(huà)實(shí)現(xiàn)背景逐漸變暗
這篇文章主要為大家詳細(xì)介紹了Android利用動(dòng)畫(huà)實(shí)現(xiàn)背景逐漸變暗的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Android仿微信底部實(shí)現(xiàn)Tab選項(xiàng)卡切換效果
這篇文章主要為大家介紹了Android仿微信底部實(shí)現(xiàn)Tab選項(xiàng)卡切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02
flutter實(shí)現(xiàn)倒計(jì)時(shí)加載頁(yè)面
這篇文章主要為大家詳細(xì)介紹了flutter實(shí)現(xiàn)倒計(jì)時(shí)加載頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Android切換至SurfaceView時(shí)閃屏(黑屏閃一下)以及黑屏移動(dòng)問(wèn)題的解決方法
本文主要介紹了Android切換至SurfaceView時(shí)閃屏(黑屏閃一下)以及黑屏移動(dòng)問(wèn)題的解決方法。具有一定的參考作用,下面跟著小編一起來(lái)看下吧2017-01-01
項(xiàng)目發(fā)布Debug和Release版的區(qū)別詳解
這篇文章主要為大家詳細(xì)介紹了項(xiàng)目發(fā)布Debug和Release版的區(qū)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
Android多個(gè)TAB選項(xiàng)卡切換效果
這篇文章主要介紹了Android多個(gè)TAB選項(xiàng)卡切換效果的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-04-04
Flutter?日歷組件簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要為大家介紹了Flutter?日歷組件簡(jiǎn)單實(shí)現(xiàn)的圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Android openGl 繪制簡(jiǎn)單圖形的實(shí)現(xiàn)示例
這篇文章主要介紹了Android openGl 繪制簡(jiǎn)單圖形的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android開(kāi)發(fā)之刪除項(xiàng)目緩存的方法
這篇文章主要介紹了Android開(kāi)發(fā)之刪除項(xiàng)目緩存的方法,結(jié)合實(shí)例形式分析了Android開(kāi)發(fā)中關(guān)于緩存的設(shè)置與刪除技巧,需要的朋友可以參考下2016-02-02

