8

I have a sealed class like so:

sealed class SealedClass {

    object Object1 : SealedClass()
    object Object2 : SealedClass()
    object Object3 : SealedClass()

    data class DataClass(val sealedClass: SealedClass, val anotherDataType: AnotherDataType? = null)
}

I would like to pass my data class in a Bundle like we normally pass values to a new fragment like so:

@JvmStatic
fun newInstance(dataClass: DataClass): Fragment {
    val fragment = Fragment()

    val args = Bundle(1)
    args.putParcelable("DATA_CLASS", dataClass)
    fragment.arguments = args

    return fragment
}

I'm not sure how to go about this. So far what I've read is that people use an @Parcelize annotation, which is an experimental feature of Kotlin that I'm trying to avoid. Another approach is to extend the data class by Parcelable and implement the Parcelable methods, but since I use custom classes as parameters in the DataClass (for instance, SealedClass), I don't know how to read/write those values inside Parcelable implementation. Is this not a right approach to go about it?

waseefakhtar
  • 1,373
  • 2
  • 24
  • 47

3 Answers3

14

I think this can be simpler now with recent Kotlin using Parcelable:

@Parcelize
data class TimeSeries(
    val sourceInfo: SourceInfo? = null,
    val variable: Variable? = null,
    val values: List<Value_>? = null,
    val name: String? = null
) : Parcelable

Then pass it in your bundle:

val intent = Intent(context, DetailsActivity::class.java).apply {
   putExtra(MY_DATA, mydata[position])
}
context.startActivity(intent)

Then bring it in through your bundle:

mydata = intent?.getParcelableExtra<TimeSeries>(MY_DATA)

If you want instead to pass a Bundle you can also just use bundleOf(MY_DATA to mydata[position]) when putting the Extra, and intent?.getBundleExtra(MY_DATA)?.getParcelable<TimeSeries>(MY_DATA) when getting it, but looks like adding another layer.

Treviño
  • 2,999
  • 3
  • 28
  • 23
11

If you want to transform the sealed class as parcelable, you can do the following:

sealed class SealedClass : Parcelable {

    @Parcelize
    object Object1 : SealedClass()

    @Parcelize
    object Object2 : SealedClass()

    @Parcelize
    object Object3 : SealedClass()

    @Parcelize
    data class DataClass(val sealedClass: SealedClass, val anotherDataType: AnotherDataType? = null) : SealedClass()
}
Dương Minh
  • 2,062
  • 1
  • 9
  • 21
  • 2
    Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made – Himanshi Thakur May 05 '21 at 05:28
3

Serializable while using reflection and causing a bit more garbage collection, is easier to implement.

I find it easiest to use GSON. https://github.com/google/gson

First, add it to your data class like this:

data class TimeSeries(
    @SerializedName("sourceInfo")
    val sourceInfo: SourceInfo? = null,
    @SerializedName("variable")
    val variable: Variable? = null,
    @SerializedName("values")
    val values: List<Value_>? = null,
    @SerializedName("name")
    val name: String? = null
) : Serializable

Then pass it in your bundle:

val intent = Intent(context, DetailsActivity::class.java).apply {
            putExtra(MY_DATA, Gson().toJson(mydata[position]))
        }
        context.startActivity(intent)

Then bring it in through your bundle:

mydata = Gson().fromJson(intent?.extras?.getString(MY_DATA), TimeSeries::class.java)
Richard Dapice
  • 838
  • 5
  • 10