Bridging Activities/Fragments using Sealed Parcelable Class

Robin Wu

--

Background:

As Jetpack Compose slowly taking over the Android world, you may be familiar with Navigation pattern with Compose.

However, if your app still has many legacy fragments/activities and you need to pass in parameters to those, it would need to pass bundle/arguments to do so, check out this stack overflow post.

My biggest complain is that when you have many parameters, you would have to first:

startActivity(Intent(this, SecondActivity::class.java).apply {
putExtra("EXTRA_NAME", "john")
putExtra("EXTRA_SEX", "male")
putExtra("EXTRA_AGE", 24)
})

And in Fragment/Activity’s onCreate or onAttach, get those parameters:

val name = intent.extras?.getString("EXTRA_NAME") ?: ""
val sex = intent.extras?.getString("EXTRA_SEX") ?: "male"
val age = intent.extras?.getInt("EXTRA_AGE") ?: 0

//See how the nullability of the getString() / getInt() causes default data?

Consider another situation that we have two ways to initialize the Activity that one needs user’s age another doesn’t. It would be a headache to do the initialization, because how would you know if a field is supposed to exist or it is simply not present because of some errors. Thus this creates lots of confusions, especially when others need to read the code you write.

For example, on version 1 of SecondActivity we need users’ name, sex and age, but on version 2 we will need only name and sex, deprecating the age attribute. Then how can we identify the difference between version 1 and 2?

Solution:

Instead of passing in each attributes individually, we can make use of the combination of Parcelable and Sealed Class.

    sealed class IntermediateData: Parcelable {
abstract val name: String
@Parcelize
class NewIntermediateData(override val name: String, val sex: String): IntermediateData()

@Parcelize
class OldIntermediateData(override val name: String, val sex: String, val age: Int): IntermediateData()
}

using either NewIntermediateData or OldIntermediateData depending on the version, we can send this as a Parcelable with the Intent:

findViewById<Button>(R.id.go_to_next_screen_button).setOnClickListener {
val newIntermediateData = SecondActivity.IntermediateData.NewIntermediateData(name = "John Foo", sex = "Male")
startActivity(Intent(this, SecondActivity::class.java).apply {
putExtra("EXTRA", newIntermediateData)
})
}
findViewById<Button>(R.id.go_to_next_screen_button_old).setOnClickListener {
val oldIntermediateData = SecondActivity.IntermediateData.OldIntermediateData(name = "Mary Ann", sex = "Female", age = 65)
startActivity(Intent(this, SecondActivity::class.java).apply {
putExtra("EXTRA", oldIntermediateData)
})
}

// please forgive me using findViewById, as that is not the focus of these code

on the receiving Activity/Fragment, we can proceed with reading the parcelable and do the parsing by its type:

private fun processData(newIntermediateData: IntermediateData?){
when(newIntermediateData){
is IntermediateData.NewIntermediateData -> {
intermediateData = newIntermediateData
viewModel.init(intermediateData as IntermediateData.NewIntermediateData)
}
is IntermediateData.OldIntermediateData -> {
intermediateData = newIntermediateData
viewModel.init(intermediateData as IntermediateData.OldIntermediateData)
}
else -> {
Log.e("SecondActivity", "failed to init second activity")
}
}
}


//In onCreate/onAttach:

processData(intent.extras?.getParcelable("EXTRA", IntermediateData::class.java))

Then you can pass those data to viewmodels’ init methods with confidence!

In my opinion, even for creating Fragments/Activity without only one version of constructor, we can still benefit from better readability as well as confidence on accessing non-nullable fields .

checkout Github repo here: https://github.com/q58wu/multiple_constructor_for_activity_and_fragment

Thanks for reading and let’s Keep On Truckin!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response