While developing Nyx, I stumbled upon a custom delegate that would get me the extras using an inner class. Similar to safeArgs. I found it a very intriguing thing for a lazy ass like me. I implemented the same for my other app Ip-Scanner but immediately realized it contains a boilerplate code. For each fragment and activity.

Being a lazy person, I hate writing boilerplate, I made few extensions that would get the extras for me with Kotlin lazy.

Activities

inline fun <reified T : Any> Activity.extra(extraKey: String, default: T? = null) = lazy {
    val value = intent?.extras?.get(extraKey)
    if (value is T) value else default
}

However, The method above can result in nullable values, If you want to have null safety and crash the flow if something is null, You can use:

inline fun <reified T : Any> Activity.extraNotNull(key: String, default: T? = null) = lazy {
    val value = intent?.extras?.get(key)
    requireNotNull(if (value is T) value else default) { key }
}

extra() would get the extras at runtime when accessing the data. extraNotNull() is same, but it would crash at runtime if the value received is null.

requireNotNull() will make sure you always receive not null values. If null was received, the flow will be interrupted with fatal exception.

Tip: Either monad with this implementation works great. It is optional. I, personally, love functional programming, and it fit with my implementation excellently.

Fragments

It is very straightforward with fragments as well:

inline fun <reified T : Any> Fragment.extra(key: String, default: T? = null) = lazy {
    val value = arguments?.get(key)
    if (value is T) value else default
}

With null safety:

inline fun <reified T : Any> Fragment.extraNotNull(key: String, default: T? = null) = lazy {
    val value = arguments?.get(key)
    requireNotNull(if (value is T) value else default) { key }
}

Just in case you were wondering what does reified means, Anything reified is made something abstract more concrete or real. Reified in Kotlin, makes Kotlin much better alternative. I am uncertain if java has something like reified, But I heavily use reified in my day-to-day development. I will write a blog post someday about this.

Usage:

Enough snippets, How would you use it in your views:

class MainActivity: AppCompatActivity() {
    // Nullable string example, It would return String?
    private val someString by extra<String>("ID_CONSTANT")
    // Not-Null string example, It always returns String
    private val someNotNullString by extraNotNull<String>("ID_CONSTANT")
}

However, If you wish to enforce the requirement of not null extras by default, You can use a custom requireNotNulls(varargs) extension. Since extras are internally lazy, You won’t be adding lazy explicitly anymore.

You can achieve that like this:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requireNotNulls(someString, someNotNullString)
    }

    private fun requireNotNulls(vararg arguments: Any?) {
        arguments.forEach {
            requireNotNull(value = it)
        }
    }
}

This approach would ensure that Activity would crash if the required extras are null.

Yes, This is a very small article, But it helped me to reduce boilerplate for extras. Though, You can simply mitigate using something like this if you prefer using safeArgs with Jetpack Navigation Component. I would strongly recommend, using Navigation component and safeArgs since it ensures such things by default. However, If you are restricted by your peers, You can come up with a solution based on this.

Thanks for reading, do let me know if you feel like adding something. Until next time.