Kotlin进阶指南 - Parcelable序列化
使用
Kotlin
期间,涉及到对象传递
的时候,都需要使用到序列化,以前我习惯Serializable
,但是Kotlin
中有些框架必须使用Parcelable
序列化方式,然后就学习了一下对象序列化插件
(注解),毕竟插件效率高一些,有时间我会记录一下原始方法实现Parcelable
的写法,最后…遇到一些问题…记录一些解决方式…
你有没有遇到过以下几个异常?
How to ignore fields when using @Parcelize annotation in Kotlin
Kotlin - How to parcelize an object variable
Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'
This is not support directly by 'Parcelize', Annotate the parameter type with @RawValue if you want it to be serialized using 'writeValue'
百尺竿头
-
-
-
- 先知
-
- 导包注意
- 使用注意
- build.gradle(app)实现插件的俩种方式
- kotlin-android-extensions 插件
- kotlin-parcelize 插件
- 兴趣扩展
-
- 如何在@Parcelize注解时忽略字段?
-
-
先知
整篇主讲kotlin-android-extensions、kotlin-parcelize
序列化插件,早期
在创建kotlin项目
时会自动引入kotlin-android-extensions
,如果没有引入的话不可使用 @Parcelize注解
,不过现在创建的kotlin项目一般都不会再自动引入!
主要因为kotlin-android-extensions 插件
的另一项功能:通过id去读取控件是会有额外的开销.所以官方已经不推荐这种写法了.
故此如果我们只用"Parcelable序列化"的话,只用“kotlin-parcelize”序列化插件 即可
在Parcelable序列化
方面,如果没有使用早期的kotlin-android-extensions插件
,那么就需要单独引入kotlin-parcelize 插件
,但是前提你kt的编译版本为1.4.20,如果是之前的版本,引入’kotlin-parcelize’则会报错
导包注意
- 使用
kotlin-android-extensions 插件
导包时导入import kotlinx.android.parcel.Parcelize
(As4.0、4.1 后均已过时
) - 使用
kotlin-parcelize 插件
导包时导入import kotlinx.parcelize.Parcelize
使用注意
kotlin-android-extensions 插件
和kotlin-parcelize 插件
不可同时使用!!!
否则 - 报错:
'kotlin-parcelize' can't be applied together with 'kotlin-android-extensions'
原因
kotlin-android-extensions 插件
包含kotlin-parcelize 插件
的功能,功能重叠了kotlin-parcelize 插件
是独立存在的,本质还是同种相斥
的结果,故只能二选一
build.gradle(app)实现插件的俩种方式
-
apply plugin
(单插件)apply plugin: 'kotlin-android-extensions'
-
plugins + id
(多插件)plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-android-extensions'
id 'com.alipay.apollo.baseline.config'
}
友情提示:plugin、plugins 设置位置
kotlin-android-extensions 插件
提示:kotlin-android-extensions 有很多功能,序列化只是其中的一部分功能而已!!!
在第一行代码第三版中有提到kotlin-android-extensions
扩展插件, 但是在as4.0之后便被抛弃
,不过可能为了兼容性,这款插件依旧是可以被引入的
build.gradle(Project)
buildscript {
ext.kotlin_version = '1.4.32'
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
//我未引入
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
build.gradle(app)
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-android-extensions'
id 'com.alipay.apollo.baseline.config'
// 以下为 序列化专用框架
//id 'kotlin-parcelize'
}
序列化
-
定义
实体类
-
添加
@Parcelize
注解 -
实现
Parcelable
接口 -
注解导包 → kotlinx.android.parcel.Parcelize
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize@Parcelize
class PersonText(
var name: String,
var age: Int
):Parcelable
kotlin-parcelize 插件
build.gradle(app)
/*序列化插件*/
apply plugin: 'kotlin-parcelize'
序列化
-
定义
实体类
-
添加
@Parcelize
注解 -
实现
Parcelable
接口 -
注解导包 → kotlinx.parcelize.Parcelize
import android.os.Parcelable
import kotlinx.parcelize.Parcelize@Parcelize
data class UserInfo(var name: String, var age: String) : Parcelable
兴趣扩展
如何在@Parcelize注解时忽略字段?
大致翻一下原文所遇问题和解决方式
使用下方序列化后,报出:Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'
@Parcelize
data class LeaderboardState(
val progressShown: Boolean = true,
val pagedList: PagedList<QUser>? = null
) : Parcelable
然后使用@Transient
依旧报错
@Parcelize
data class LeaderboardState(
val progressShown: Boolean = true,
//Same error
@Transient
val pagedList: PagedList<QUser>? = null
) : Parcelable
使用@IgnoredOnParcel
依旧报错
@Parcelize
data class LeaderboardState(
val progressShown: Boolean = true,
//Same error plus lint error on annotation
@IgnoredOnParcel
val pagedList: PagedList<QUser>? = null
) : Parcelable
最终作者采纳了一个答案,如下
使用常规类并将属性移出主要构造函数
@Parcelize
class LeaderboardState(
val progressShown: Boolean = true,
pagedList: PagedList<QUser>? = null
) : Parcelable {
@IgnoredOnParcel
val pagedList: PagedList<QUser>? = pagedList
}
这显然是唯一的解决方案。确保根据需要覆盖equals,hashCode,toString,copy等,因为它们不会为常规类定义。
编辑:这是另一个解决方案,因此您不会丢失数据类的功能,也不会丢失自动打包。我在这里使用一般示例。
data class Person(
val info: PersonInfo
val items: PagedList<Item>? = null)
@Parcelize
data class PersonInfo(
val firstName: String,
val lastName: String,
val age: Int
) : Parcelable
您只保存Person.info
并从中重新创建它。