'How to use Parcel.readTypedList() along with @Parcelize from kotlin-android-extensions?
I'm running into a problem with implementing Parcelable-based state persistence in a View. Namely, as I need to implement the methods of BaseSavedState
like this:
class SavedState : BaseSavedState {
lateinit var myList: ArrayList<MyParcelable>
constructor(superState: Parcelable) : super(superState) {}
private constructor(parcel: Parcel) : super(parcel) {
val listSize = parcel.readInt()
val list = ArrayList<MyParcelable>(listSize)
this.myList = parcel.readTypedList(list, /* needs MyParcelable.CREATOR */ )
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeInt(myList.size())
out.writeTypedList(myList)
}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(`in`: Parcel): SavedState {
return SavedState(`in`)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
}
However, as you can see, I can't seem to use Parcel.readTypedList()
because it needs both the typed list, and the parcelable's CREATOR
field!
Classes marked like:
@Parcelize
data class MyParcelable(val someData: String): Parcelable {
}
Do not have CREATORs, in fact, if you try to implement, it says:
'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.
I do not want a Parceler companion object, I need a CREATOR!
I also kinda don't want to write the Parcelable implementation by hand, so I might just make it Serializable and be like "whatever".
Does anyone know by chance how you can use Parcel.readTypedList()
with @Parcelize
-annotated Kotlin data class?
Solution 1:[1]
https://github.com/JetBrains/kotlin/commit/fc013c6b9f5f3083d06385803ff687dc9a6ab4f0#
From Kotlin 1.6.21, we can use parcelableCreator() from
import kotlinx.parcelize.parcelableCreator
val dataClass = TestDataClass("someValue")
val creator = parcelableCreator<TestDataClass>()
val parcel: Parcel? = null
parcel?.createTypedArrayList(creator) // Will compile
Solution 2:[2]
It's a bug on the Parcelize plugin like you mentioned https://youtrack.jetbrains.com/issue/KT-19853 and it can be solved by either reflection or actually, you can have a proxy class to java as you can access that CREATOR
field in java without any problems.
I made a util java class for all creators and then made a kotlin extension referring to that creator
Java
@NonNull
public static Parcelable.Creator<Blah> getBlahCreator() {
return Blah.CREATOR;
}
Kotlin
val Blah.Companion.CREATOR: Parcelable.Creator<Blah>
get() = UtilClass.getBlahCreator()
And now I can access Blah.CREATOR
anywhere! And those two classes that have all the creators and extensions could be just deleted later after the bug got fixed in the foreseeable future and it'll just work as expected without any edits in the other classes that use the CREATOR
This feels much better to me than the reflection solution! but either way, they are both disgusting and I hope this bug could be fixed soon enough!
Solution 3:[3]
Upvoted for the question as I encounter the same problem in one of class, but its not visible as I am a new user. I used the below alternative,(readArrayList)though it has are minor difference
readTypedList
arrayListOf<YourParcelableClass>().apply { parcel.readArrayList(YourParcelableClass::class.java.classLoader) }
Thanks for accepted solution but not sure why, even in java class file I am not able to read the CREATOR field.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Bagadeshkumar R |
Solution 2 | |
Solution 3 | Suraj Rao |