13

I am trying to write a kotlin extension function for Context which will start a new activity in android with given class name and list of intent extras. I am able to successfully start activity without any extras but I am facing problem with them.

fun <T> Context.openActivity(it: Class<T>, pairs: List<Pair<String, Any>>) {
  var intent = Intent()
  pairs.forEach {
     intent.putExtra(it.first, it.second)
  }
  startActivity(intent)
}

Main issue here is -> intent.putExtra() doesn't except second param as Any

Sergio
  • 27,326
  • 8
  • 128
  • 149
Saksham Khurana
  • 872
  • 13
  • 26

6 Answers6

25

Instead of using a list of pairs, consider using a Bundle. Then you can add it with putExtras(Bundle).

If you want to go one step ahead, you could add a lambda extension to configure the extras:

fun <T> Context.openActivity(it: Class<T>, extras: Bundle.() -> Unit = {}) {
  val intent = Intent(this, it)
  intent.putExtras(Bundle().apply(extras))
  startActivity(intent)
}

Then you can call it as:

openActivity(MyActivity::class.java) {
  putString("string.key", "string.value")
  putInt("string.key", 43)
  ...
}
Jéwôm'
  • 3,753
  • 5
  • 40
  • 73
tynn
  • 38,113
  • 8
  • 108
  • 143
  • Thanks for this brilliant lambda extension approach. Can you please redirect me to a site where I can read more about this as a want to understand the concept of this extension approach. Thanks in advance. – Saksham Khurana Dec 16 '18 at 16:49
  • 1
    intent.addExtras(Bundle().apply(extras)) 1)This doesn't exist 2) If I want to add flag in intent how? – Subho Aug 29 '19 at 11:05
  • @Subho 1 was a spelling issue. The text was more exact about it. For 2 you'd have to implement `openActivity` to also set the flag to the intent or use a closure with `Intent` as a receiver instead. – tynn Aug 29 '19 at 11:46
  • Are you referring to my answer? @tynn – Subho Sep 03 '19 at 11:42
17

Declare:

inline fun <reified T : Activity> Context.startActivity(block: Intent.() -> Unit = {}) {
    startActivity(Intent(this, T::class.java).apply(block))
}

Simple using:

startActivity<MainActivity>()

With extra

startActivity<MainActivity>{
   putExtra("param 1", "Simple")
}
Wilson Tran
  • 4,050
  • 3
  • 22
  • 31
3

Here is the extension function for start activity:

inline fun <reified T : Activity> Context.openActivity(vararg params: Pair<String, Any>) {
    val intent = Intent(this, T::class.java)
    intent.putExtras(*params)
    this.startActivity(intent)
}

fun Intent.putExtras(vararg params: Pair<String, Any>): Intent {
    if (params.isEmpty()) return this
    params.forEach { (key, value) ->
        when (value) {
            is Int -> putExtra(key, value)
            is Byte -> putExtra(key, value)
            is Char -> putExtra(key, value)
            is Long -> putExtra(key, value)
            is Float -> putExtra(key, value)
            is Short -> putExtra(key, value)
            is Double -> putExtra(key, value)
            is Boolean -> putExtra(key, value)
            is Bundle -> putExtra(key, value)
            is String -> putExtra(key, value)
            is IntArray -> putExtra(key, value)
            is ByteArray -> putExtra(key, value)
            is CharArray -> putExtra(key, value)
            is LongArray -> putExtra(key, value)
            is FloatArray -> putExtra(key, value)
            is Parcelable -> putExtra(key, value)
            is ShortArray -> putExtra(key, value)
            is DoubleArray -> putExtra(key, value)
            is BooleanArray -> putExtra(key, value)
            is CharSequence -> putExtra(key, value)
            is Array<*> -> {
                when {
                    value.isArrayOf<String>() ->
                        putExtra(key, value as Array<String?>)
                    value.isArrayOf<Parcelable>() ->
                        putExtra(key, value as Array<Parcelable?>)
                    value.isArrayOf<CharSequence>() ->
                        putExtra(key, value as Array<CharSequence?>)
                    else -> putExtra(key, value)
                }
            }
            is Serializable -> putExtra(key, value)
        }
    }
    return this
}

Simple using:

openActivity<TestActivity>("key0" to "value0", "key1" to "value1")

A simpler approach is provided in Kotlin

Use the bundleOf()

inline fun <reified T : Activity> Context.openActivity1(vararg params: Pair<String, Any?>) {
    val intent = Intent(this, T::class.java)
    intent.putExtras(bundleOf(*params))
    this.startActivity(intent)
}

midFang
  • 96
  • 3
2

Here is the extension function for start activity:

inline fun <reified T : Activity> Context.openActivity(noinline extra: Intent.() -> Unit) {
      val intent = Intent(this, T::class.java)
      intent.extra()
      startActivity(intent)
}

You can call this function like this way:

openActivity<MyActivity> {
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    putExtra(LaBoxConstants.DEFAULT_LANDING, Default_Landing)
    putExtra(HomeActivity.APP_RELAUNCH, AppReLaunched)
}

NOTE: IT IS NOT A RECOMMENDED WAY TO START ACTIVITY. USE STARTACTIVITY INSTEAD.

Subho
  • 539
  • 1
  • 9
  • 25
2

I personally prefer an approach where I have a method that defines the flag for an activity, to prevent having to re-write the flags for every startActivity invocation.

internal inline fun <reified T: Activity> Context.startActivity(activity: KClass<T>, noinline modifyIntent: Intent.() -> Unit) {
    val intent = Intent(this, activity.java)
        .addFlags(flagsForActivity(activity))
        .modifyIntent()

    startActivity(intent)
}

private fun <T: Activity> flagsForActivity(activity: KClass<T>): Int {
    return when (activity) {
        LoginActivity::class -> Intent.SPECIFIC_FLAGS
        else -> Intent.DEFAULT_FLAGS
    }
}

And then the way it would be called is

startActivity(LoginActivity::class) {
    putExtra("Username", "username")
}
1

There is no method putExtra(String, Any) in the Intent object. You can use Bundle object to save your data:

fun <T> Context.openActivity(it: Class<T>, bundleKey: String, bundle: Bundle) {
    var intent = Intent(this, it)
    intent.putExtra(bundleKey, bundle)
    startActivity(intent)
}

To call it inside Context object:

val bundle = Bundle()
bundle.putString("Key", "Value") // you can put another object here
openActivity(SomeActivity::class.java, "Bundle Key", bundle)
Sergio
  • 27,326
  • 8
  • 128
  • 149