Search code examples
androidandroid-architecture-navigationkotlin-multiplatformandroid-safe-args

How to use safe-args with MPP serializable data


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.


Solution

  • As CommonsWare suggested, use @Parcelize (and by extension, Parcelable)

    enter image description here

    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()

    will look like this: enter image description here

    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