I'm trying to use safe-args with kotlin-multiplatform types, however I keep geting the same issue during run-time when trying to pass serializable data:
Caused by: java.lang.IllegalArgumentException: org.kotlin.mpp.mobile.models.MyModel is not Serializable or Parcelable.
In my nav_host.xml I have the following:
<fragment
android:id="@+id/aFragment"
android:name="com.corp.myapp.main.aFragment"
android:label="aFragment" >
<action
android:id="@+id/action_aFragment_to_bFragment"
app:destination="@id/bFragment"
app:popUpTo="@id/bFragment"
app:popUpToInclusive="true">
<argument
android:name="myname"
app:argType="org.kotlin.mpp.mobile.models.MyModel"
app:nullable="true" />
</action>
</fragment>
Two approaches I'm using right now where i get the exact same exception.
First one is by using the kotlinx-serialization plugin where i have the following type:
package org.kotlin.mpp.mobile.models
import kotlinx.serialization.Serializable
@Serializable
data class MyModel(val first: String = "", val last: String = "")
Second one I tried by as first one didn't work was to make a platform specific (JVM) implementation with an extension of java.io.Serializable with the following:
commondataModels.kt:
package org.kotlin.mpp.mobile.models
expect class MyModel(first: String, last: String)
actualdataModels.kt:
package org.kotlin.mpp.mobile.models
import java.io.Serializable
actual data class MyModel actual constructor(val first: String, val last: String): Serializable
I'm making the navigation call in my Activity with the generated direction class:
import org.kotlin.mpp.mobile.models.*
val user = MyModel("Bruce","Lee")
host.findNavController().navigate(AFragmentDirections.actionAFragmentToBFragment(user))
Thanks in advance for any advice!
NOTE: I can make everything work by passing a Bundle with the navigate API, however I would like it to work with safe-args.
As CommonsWare suggested, use @Parcelize (and by extension, Parcelable)
The trick is to make sure that Parcelable doesn't break your common code, as this is Android only concept. For this, in your common code add
expect interface Parcelable
as well as:
@UseExperimental(ExperimentalMultiplatform::class) @OptionalExpectation @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) expect annotation class Parcelize()
Then in your Android source set, typealias in actual:
actual typealias Parcelable = android.os.Parcelable
actual typealias Parcelize = kotlinx.android.parcel.Parcelize
In other source sets (such as iOS), just put this into actual:
actual interface Parcelable