adrielcafe / voyager

🛸 A pragmatic navigation library for Jetpack Compose
https://voyager.adriel.cafe
MIT License
2.58k stars 135 forks source link

How can I save a screen which have @Serializable args on Android? #501

Closed kagg886 closed 13 hours ago

kagg886 commented 2 weeks ago

this is my screen defination:

class IllustDetailScreen(private val illust0: Illust) : Screen

@Serializable
data class Illust(
    val id: Int,
    val title: String,
)

when i press home on emulator, the app was crash and logged this error:

                                                                                                    android.os.BadParcelableException: Parcelable encountered IOException writing serializable object (name = top.kagg886.pmf.ui.route.main.detail.illust.IllustDetailScreen)
at android.os.Parcel.writeSerializable(Parcel.java:2797)
at android.os.Parcel.writeValue(Parcel.java:2563)
at android.os.Parcel.writeValue(Parcel.java:2362)
at android.os.Parcel.writeList(Parcel.java:1415)
at android.os.Parcel.writeValue(Parcel.java:2506)
at android.os.Parcel.writeValue(Parcel.java:2362)
at android.os.Parcel.writeList(Parcel.java:1415)
at android.os.Parcel.writeValue(Parcel.java:2506)
at android.os.Parcel.writeValue(Parcel.java:2362)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843)
at android.os.Bundle.writeToParcel(Bundle.java:1389)
at android.os.Parcel.writeBundle(Parcel.java:1367)
at android.os.Parcel.writeValue(Parcel.java:2479)
at android.os.Parcel.writeValue(Parcel.java:2369)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843)
at android.os.Bundle.writeToParcel(Bundle.java:1389)
at android.os.Parcel.writeBundle(Parcel.java:1367)
at android.os.Parcel.writeValue(Parcel.java:2479)
at android.os.Parcel.writeValue(Parcel.java:2369)
at android.os.BaseBundle.dumpStats(BaseBundle.java:1917)
at android.os.BaseBundle.dumpStats(BaseBundle.java:1954)
at android.app.servertransaction.PendingTransactionActions$StopInfo.collectBundleStates(PendingTransactionActions.java:123)
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:139)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                                                                                                    Caused by: java.io.NotSerializableException: top.kagg886.pixko.module.illust.Illust
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1620)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1581)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1490)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
at android.os.Parcel.writeSerializable(Parcel.java:2792)
at android.os.Parcel.writeValue(Parcel.java:2563) 
at android.os.Parcel.writeValue(Parcel.java:2362) 
at android.os.Parcel.writeList(Parcel.java:1415) 
at android.os.Parcel.writeValue(Parcel.java:2506) 
at android.os.Parcel.writeValue(Parcel.java:2362) 
at android.os.Parcel.writeList(Parcel.java:1415) 
at android.os.Parcel.writeValue(Parcel.java:2506) 
at android.os.Parcel.writeValue(Parcel.java:2362) 
at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298) 
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 
at android.os.Bundle.writeToParcel(Bundle.java:1389) 
at android.os.Parcel.writeBundle(Parcel.java:1367) 
at android.os.Parcel.writeValue(Parcel.java:2479) 
at android.os.Parcel.writeValue(Parcel.java:2369) 
at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298) 
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 
at android.os.Bundle.writeToParcel(Bundle.java:1389) 
at android.os.Parcel.writeBundle(Parcel.java:1367) 
at android.os.Parcel.writeValue(Parcel.java:2479) 
at android.os.Parcel.writeValue(Parcel.java:2369) 
at android.os.BaseBundle.dumpStats(BaseBundle.java:1917) 
at android.os.BaseBundle.dumpStats(BaseBundle.java:1954) 
at android.app.servertransaction.PendingTransactionActions$StopInfo.collectBundleStates(PendingTransactionActions.java:123) 
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:139) 
at android.os.Handler.handleCallback(Handler.java:958) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loopOnce(Looper.java:205) 
at android.os.Looper.loop(Looper.java:294) 
at android.app.ActivityThread.main(ActivityThread.java:8177) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

I was puzzled that the Saver seems think it is all Parcelable, so can we support the @Serializable tag?

kotlin-compose-multiplatform commented 1 week ago

Add this package: https://github.com/icerockdev/moko-parcelize

Add @Parcelize annotation and Parcelable implementation to your Screen class and data classes:

@Parcelize
class IllustDetailScreen(private val illust0: Illust) : Screen,Parcelable

@Parcelize
@Serializable
data class Illust(
    val id: Int,
    val title: String,
): Parcelable
hoc081098 commented 1 week ago

Check out https://hoc081098.github.io/kmp-viewmodel/docs/0.x/viewmodel-savedstate/

kagg886 commented 1 day ago

this Illust class has the property typed kotlinx.datetime.Instant

it not be serialized,can we do it by @Parcelize

kotlin-compose-multiplatform commented 15 hours ago

In this example Parcelize: kotlinx.datetime.LocalDateTime

Click here

kagg886 commented 13 hours ago

In this example Parcelize: kotlinx.datetime.LocalDateTime

Click here

it works, thks!