Pass data between activities

To add a reminder, the user will click a button from the List activity — the activity that shows the current list of reminders. The List activity will open a Reminder setup activity that contains a text box, and in the future some affordance to set the location and possibly day and time. When the user validates, the Reminder setup activity will return the new reminder for the List activity to save.

Pass data between activities

The list activity starts SetReminderActivity by calling startActivityForResult and collects the result in the onActivityResult callback when SetReminderActivity returns.

pass-data-between-activities-4

The value for RC_NEW_REMINDER is random and does not matter.

private val RC_NEW_REMINDER = 4933

fun newReminder(view: View) {
    startActivityForResult(Intent(this, SetReminderActivity::class.java), RC_NEW_REMINDER)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == RC_NEW_REMINDER) {
        val reminder = /* deserialize from data */
        addReminder(reminder)
    }
}

In SetReminderActivity, we add an Add button to return the Reminder.

fun done(view: View) {
    var reminder = Reminder(labelText.text.toString(), listOf())
    intent.putExtra("reminder", reminder)
    setResult(RESULT_OK, intent)
    finish()
}

This won't compile just yet because putExtra expects some serializable object. We have two ways to do it: Parcelable or Serializable.

Parcelable vs Serializable

I started digging into Parcelable, before realizing Serializable would be better for my use case. The reason why Parcelable is not the best solution here is that this mechanism is mainly for different processes to share data. They call it IPC, Inter-process communication. Serializable is much more straightforward and requires less code.

Parcelable

When using Parcelable, classes implement the code to persist their data into a Parcel, and they provide a constructor to initialize their data from a Parcel. They also have a CREATOR static field which provides the method createFromParcel.

Android Studio can generate most of the code for you.

Screen-Shot-2017-09-23-at-9.52.55-AM

I only had to customize how to serialize the list of Triggers in createFromParcel and deserialize the list of Triggers in constructor(parcel: Parcel).

package com.wafrat.rappel.data

import android.os.Parcel
import android.os.Parcelable

class Reminder(val label: String, val triggers: List<Trigger>) : Parcelable {
    constructor(parcel: Parcel) : this(
            parcel.readString(),
            mutableListOf<Trigger>().apply {
                parcel.readTypedList(this, Trigger.CREATOR)
            })

    constructor() : this("", listOf())

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(label)
        // Persist the list of triggers
        parcel.write...
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Reminder> {
        override fun createFromParcel(parcel: Parcel): Reminder {
            return Reminder(parcel)
        }

        override fun newArray(size: Int): Array<Reminder?> {
            return arrayOfNulls(size)
        }
    }
}

Then in the ListActivity, I deserialized the result like so:

val reminder = data!!.getParcelableExtra<Reminder>("reminder")

There are also libraries out there that will generate most of the code for you if you add the right annotations.

Serializable

You can read the documentation on Serializable. By making your class implement this interface, you will be able to serialize and deserialize the entire state.

package com.wafrat.rappel.data

import java.io.Serializable

class Reminder(val label: String, val triggers: List<Trigger>) : Serializable {
    constructor() : this("", listOf())
}

Then I deserialized like so:

val reminder = data!!.getSerializableExtra("reminder") as Reminder

More on serialization

This is not useful in this particular case, but I also stumbled upon this Kotlin extension that lets you serialize a class into JSON, Protobuf or CBOR. I had not heard of CBOR before. Apparently it is kind of like JSON in binary format. As of writing, it was just publicly released yesterday! Neat, I might need it some day...

Now what?

The app now supports adding new reminders, but not marking them as done nor reordering them. This is the topic of our upcoming post on Lists.