Kotlin 数据类中的函数作为参数导致打包错误
Posted
技术标签:
【中文标题】Kotlin 数据类中的函数作为参数导致打包错误【英文标题】:Function in Kotlin data class as argument leads to parceling error 【发布时间】:2018-08-29 05:56:15 【问题描述】:我在 Kotlin 中有一个数据类,它使用 @Parcelize
注释来轻松打包。问题是我现在想将一个函数传递给这个类,但我真的不知道如何在打包过程中不考虑该函数。
这是我的数据类:
@Parcelize
data class GearCategoryViewModel(
val title: String,
val imageUrl: String,
val categoryId: Int,
val comingSoon: Boolean,
@IgnoredOnParcel val onClick: (gearCategoryViewModel: GearCategoryViewModel) -> Unit
) : DataBindingAdapter.LayoutViewModel(R.layout.gear_category_item), Parcelable
我尝试使用@IgnoredOnParcel
和@Transient
没有成功。
这是我得到的编译错误:
错误:(20, 39) 'Parcelize' 不直接支持类型。如果您希望使用 'writeValue()' 对其进行序列化,请使用 '@RawValue' 注释参数类型
而且这个@RawValue
注解也不起作用。
【问题讨论】:
我现在想将一个函数传递给这个类你需要什么以及你想要实现什么 @Raghunandan 我希望这个类接收一个函数的实现,以便它可以通过数据绑定来执行它。但我也需要这个类是可分割的,所以它的数据可以发送到其他活动等。 用title、imageUrl、categoryId 和comingSoon 创建另一个对象然后使这个对象Parcelable 并将这个相同的对象传递给您的viewModel 可能会更有用。data class GearCategoryViewModel(val someObject: parcelableObject, val onClick: (gearCategoryViewModel: GearCategoryViewModel) -> Unit)
这样您就不会尝试序列化 Function
。
【参考方案1】:
只需将 lambda 转换为可序列化,然后从
创建对象@Parcelize
data class GearCategoryViewModel(
val title: String,
val imageUrl: String,
val categoryId: Int,
val comingSoon: Boolean,
@IgnoredOnParcel val onClick: Serializable
) : DataBindingAdapter.LayoutViewModel(R.layout.gear_category_item), Parcelable
fun onClicked() = onClick as (gearCategoryViewModel: GearCategoryViewModel) -> Unit
companion object
fun create(
title: String,
imageUrl: String,
categoryId: Int,
comingSoon: Boolean,
onClick: (gearCategoryViewModel: GearCategoryViewModel) -> Unit
): GearCategoryViewModel = GearCategoryViewModel(
title,
imageUrl,
categoryId,
comingSoon,
onClick as Serializable
)
【讨论】:
它不工作。【参考方案2】:@Parcelize
data class GearCategoryViewModel(
val title: String,
val imageUrl: String,
val categoryId: Int,
val comingSoon: Boolean,
val onClick: @RawValue (gearCategoryViewModel: GearCategoryViewModel) -> Unit
) : DataBindingAdapter.LayoutViewModel(R.layout.gear_category_item), Parcelable
将@RawValue 与 onClick 参数一起使用。
【讨论】:
【参考方案3】:我知道这不是一个真正的答案,但我会这样做。用这样的类替换你的函数:
open class OnClick() : Parcelable
companion object
@JvmStatic
fun fromLambda(func: (GearCategoryViewModel) -> Unit) = object : OnClick()
override fun invoke(param: GearCategoryViewModel) = func(param)
@JvmField
val CREATOR = object : Parcelable.Creator<OnClick>
override fun createFromParcel(parcel: Parcel) = OnClick(parcel)
override fun newArray(size: Int) = arrayOfNulls<OnClick>(size)
constructor(parcel: Parcel) : this()
open operator fun invoke(param: GearCategoryViewModel)
throw UnsupportedOperationException("This method needs to be implemented")
override fun writeToParcel(parcel: Parcel, flags: Int) = Unit
override fun describeContents() = 0
并像这样使用它:
val onClick = OnClick.fromLambda vm -> /* do something*/
onClick(viewModel);
【讨论】:
它不会工作,因为你不写/读任何东西到/从包裹。但是您可以通过将 lambda 作为 Serializable 保存到 parcel 中来强制它工作。【参考方案4】:问题的前提并没有真正的意义。
如果你不序列化它的所有属性,你就不能反序列化这个对象。
如果这是反序列化的,您似乎希望 onClick
成为 null
,但即使这是可能的,它也会抛出 NPE,因为此属性未被标记为可为空。
考虑更改您的架构,以便仅序列化简单对象(POJO 或数据类)而不是函数。
【讨论】:
以上是关于Kotlin 数据类中的函数作为参数导致打包错误的主要内容,如果未能解决你的问题,请参考以下文章