【问题标题】:How to create from parcel with Kotlin @Parcelize?如何使用 Kotlin @Parcelize 从包裹创建?
【发布时间】:2022-07-06 02:49:45
【问题描述】:

我正在尝试将 Parcelable 模型从 Java 迁移到 Kotlin。

我的模型如下所示:

import kotlinx.parcelize.*

@Parcelize
class SignatureAuthorityModel
    (var id: Int,
    var cloudId: Int,
    var uuid: UUID?): android.os.Parcelable
{
    override fun equals(other: Any?): Boolean
    {
        //equals implementation
    }

    override fun hashCode(): Int
    {
       //some hash implementation
    }

    override fun toString(): String
    {
       //some stringifier implementation
    }
}

我可以为此模型调用 writeToParcel,但 SignatureAuthorityModel.createFromParcel(parcel) 不可用。我必须单独编写它,还是必须以某种方式配置 kotlin-parcelize 插件?从 kotlin 文档来看,当我使用 @Parcelize 注释时,似乎也应该自动生成 createFromParcel ,并且只有当我有一些高级逻辑时,我才必须在伴随对象 Creator 中编写实现.正确的做法是什么?

【问题讨论】:

    标签: android kotlin parcel


    【解决方案1】:

    如果你使用@Parcelize注解,那么你不需要写createFromParcel方法。因为@Parcelize在内部管理createFromParcel方法。

    只需像下面这样编写您的数据类。并且可能是您对 Parcelable 的错误导入,您的课程应该如下所示。

    import kotlinx.parcelize.Parcelize
    
    @Parcelize
    class User(val firstName: String, val lastName: String, val age: Int): Parcelable
    

    【讨论】:

    • 嗯,问题是我不能用这个方法,android studio IDE 找不到,kotlin 编译器也找不到。我试过 SignatureAuthorityModel.createFromParcel、SignatureAuthorityModel.Creator.createFromParcel 和 SignatureAuthorityModel.CREATOR.createFromParcel
    • 至于导入,如果我尝试只编写 Parcelable,我会收到未解决的参考错误,提示将其更改为 android.os.Parcelable,没有其他变体
    • @CrazySage 是的,我告诉过你,如果你使用的是@Parcelize,我们没有这些方法。
    • 好的,但是还有什么可以从包裹中创建对象呢?)
    • 我能知道你为什么要使用这些方法吗?否则你不必使用@Parcelize
    【解决方案2】:

    使用@Parcelize 时无法访问创建者似乎是一个已知问题

    查看 5 年前创建的此问题:https://youtrack.jetbrains.com/issue/KT-19853

    跟随那里的 cmets,他们似乎没有做任何事情。

    我个人的看法是,他们可能不会为此烦恼,因为对于最常见的用例来说,这不是必需的。在 Android 开发中 Parcelable 最常见的用例是使用 intent.putExtra()intent.putParcelableArrayListExtra() 将对象从一个 Activity 传递到另一个 Activity,在这种情况下,自动转换为 Parcel 并返回。

    编辑:
    嗯..实际上他们在这里提到https://github.com/JetBrains/kotlin/pull/4575 应该可以使用parcelableCreator 使用它,但我不知道如何使用它,或者它是否实际上是最新版本

    【讨论】:

      【解决方案3】:

      根据this pull request,有一种方法可以访问CREATOR,同时仍然使用@Parcelize 注释。我无法发现如何只阅读 PR 或文档。

      但是,我确实设法(在 PR 中)找到了一个令人愉快的小功能,该功能迄今为止很成功。我很容易地将它复制并粘贴到我的项目中。调用它将返回一个CREATOR,然后您可以从中调用createFromParcel(parcel)

      public inline fun <reified T : Parcelable> parcelableCreator(): Parcelable.Creator<T> =
      T::class.java.getDeclaredField("CREATOR").get(null) as? Parcelable.Creator<T>
          ?: throw IllegalArgumentException("Could not access CREATOR field in class ${T::class.simpleName}")
      

      下面是一个简单测试中的使用示例,该测试先进行包裹,然后从包裹中创建。

      @Test
      fun `UserDto parcelizes then unparcelizes`() {
          val parcel = Parcel.obtain()
          inputUserDto.writeToParcel(parcel, 0)
          parcel.setDataPosition(0)
      
          val userDtoFromParcel = parcelableCreator<UserDto>().createFromParcel(parcel)
      
          assertThat(inputUserDto).isEqualTo(userDtoFromParcel)
      }
      

      这是一个link,正是我在其中找到了辅助内联函数的位置。它可能并非在所有情况下都有效,但到目前为止对我来说都很好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-04
        • 1970-01-01
        相关资源
        最近更新 更多