Kotlin扩展函数启动带有Intent extras的活动

14

我正在尝试编写一个针对Context的Kotlin扩展函数,该函数可以使用给定的类名和意图附加项在Android中启动新活动。 我能够成功地启动没有任何额外项的活动,但是它们让我遇到了问题。

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)
}

这里的主要问题是 -> intent.putExtra() 不接受第二个参数为 Any

6个回答

26

考虑使用 Bundle 而非一系列的键值对。这样您可以使用 putExtras(Bundle) 添加它。

如果您想更进一步,可以添加一个 lambda 扩展来配置 extras:

fun <T> Context.openActivity(it: Class<T>, extras: Bundle.() -> Unit = {}) {
  val intent = Intent(this, it)
  intent.putExtras(Bundle().apply(extras))
  startActivity(intent)
}
然后您可以这样称呼它:
openActivity(MyActivity::class.java) {
  putString("string.key", "string.value")
  putInt("string.key", 43)
  ...
}

感谢这个出色的Lambda扩展方法。您能否将我重定向到一个网站,让我可以阅读更多关于这个扩展方法的概念。提前致谢。 - Saksham Khurana
1
intent.addExtras(Bundle().apply(extras))
  1. 这个不存在
  2. 如果我想在意图中添加标志,该怎么做?
- Subho
@Subho 1 是一个拼写问题。文本对此更加精确。对于2,您需要实现openActivity以设置意图的标志,或者使用将Intent作为接收器的闭包。 - tynn
你是在提到我的回答吗?@tynn - Subho

18

声明:

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

简单使用:

startActivity<MainActivity>()

额外的功能

startActivity<MainActivity>{
   putExtra("param 1", "Simple")
}

2
此外,你也可以使用 intent.block() 或者 Intent(this, T::class.java).apply(block) 来代替 block(intent) - Subaru Tashiro
@SubaruTashiro,你能否展示一下你所建议的完整代码吗?看起来更好。 - android developer
内联函数 <reified T : Activity> Context.startActivity(block: Intent.() -> Unit = {}) { startActivity(Intent(this, T::class.java).apply(block)) } - Cypher
感谢Subaru Tashiro和Crypher的帮助,我刚刚编辑了我的答案。 - Wilson Tran
编写扩展类的惊人方法 - blueware

3

这是启动活动的扩展函数:

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
}

使用简单:

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

在Kotlin中提供了更为简单的方法

使用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)
}


1
嗨,你可以在Kotlin中使用bundleOf()来传递Android Kotlin中的参数。 - Nafis Kabbo
1
@NafisKabbo,我刚刚发现了这个方法。非常方便,谢谢你。 - midFang

2

我个人更喜欢一种方法,即使用一个定义了活动标志的方法,以避免在每次启动活动时都重新编写标志。

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
    }
}

然后它将被称为:

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

2
这是启动活动的扩展函数:

最初的回答:

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

您可以这样调用此函数:
openActivity<MyActivity> {
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    putExtra(LaBoxConstants.DEFAULT_LANDING, Default_Landing)
    putExtra(HomeActivity.APP_RELAUNCH, AppReLaunched)
}

注意:这不是启动Activity的推荐方式,请使用startActivity代替。

最初的回答


4
为什么这不是一个推荐的开始活动的方式?对我来说,这似乎非常方便。 - Subaru Tashiro

1

Intent 对象中没有 putExtra(String, Any) 方法。您可以使用 Bundle 对象来保存数据:

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

Context 对象中调用它:

val bundle = Bundle()
bundle.putString("Key", "Value") // you can put another object here
openActivity(SomeActivity::class.java, "Bundle Key", bundle)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接