有没有办法在活动之间传递函数引用?

Mil*_*nka 8 android kotlin

有没有办法在Kotlin和Android中捆绑函数引用,以便可以从其他片段调用函数?例如,我的片段工厂方法如下所示:

    fun newInstance(tryAgainFunction: () -> Unit): TimeOutHandlerFragment {
        val fragment = TimeOutHandlerFragment()
        val bundle = Bundle()

        return fragment
    }
Run Code Online (Sandbox Code Playgroud)

我希望能够将我的tryAgainFunction保存在bundle中以便进一步检索.

非常感谢!

编辑

最后,最合适的解决方案是使用热键的答案,然后在onViewCreated中使用传递的函数初始化一个侦听器.完整的代码如下:

companion object {
    val CALLBACK_FUNCTION: String = "CALLBACK_FUNCTION"

    fun newInstance(tryAgainFunction: () -> Unit): TimeOutHandlerFragment {
        val fragment = TimeOutHandlerFragment()
        val bundle = Bundle()
        bundle.putSerializable(CALLBACK_FUNCTION, tryAgainFunction as Serializable)
        fragment.arguments = bundle
        return fragment
    }
}

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    try {
        val callback: () -> Unit = arguments.getSerializable(CALLBACK_FUNCTION) as () -> Unit
        btnTryAgain.setOnClickListener { callback.invoke() }
    } catch (ex: Exception) {
        // callback has a wrong format
        ex.printStackTrace()
    }
}
Run Code Online (Sandbox Code Playgroud)

感谢大家的帮助!

Sam*_*hen 12

2022 年更新:

  1. 我原来的方法有一个缺点,在我的演示中,如果我按主页按钮将应用程序置于后台,它将崩溃并显示 NotSerializableException.
  2. 实际上还有另一个 API 只是用于监听另一个 API 的更改Fragment,即FragmentResultListener官方教程在这里: https: //youtu.be/oP-zXjkT0C0?t =468 。
  3. 如果FragmentResultListener不能满足您的需求,Shared ViewModel最终解决方案在那里: https: //youtu.be/THt9QISnIMQ

1.您需要添加id 'kotlin-parcelize'到您的build.gradle(应用程序)中,如下所示:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'kotlin-parcelize'    //here
}
Run Code Online (Sandbox Code Playgroud)

2. 创建一个类来包装您的 Lambda 函数:

@Parcelize
class Listener(val clickAction: () -> Unit) : Parcelable {
    fun onClick() = clickAction()
}
Run Code Online (Sandbox Code Playgroud)

3. 传递您的 Lambda:

val bundle = Bundle().apply {
    putParcelable("listener", Listener(clickAction))
}

private val clickAction: () -> Unit = {    
    //do your stuff
}
Run Code Online (Sandbox Code Playgroud)

4. 检索:

arguments?.getParcelable<Listener>("listener")?.onClick()
Run Code Online (Sandbox Code Playgroud)

演示(全部Fragment): https: //youtu.be/0OnaW4ZCnbk

  • 与所有其他解决方案一样,当片段活动进入后台堆栈时,我会收到 NotSerializedException。 (8认同)
  • 当活动进入返回堆栈时,有人找到了 NotSerializedException 的解决方案吗? (3认同)

hot*_*key 7

如果tryAgainFunctionSerializable,则可以将其放入bundle使用中bundle.putSerializable("try_again_function", tryAgainFunction);

实际上Serializable是函数引用(SomeClass::someFunction)还是lambda。但是,如果它是功能接口的某些自定义实现,则可能不是() -> Unit,所以您应该检查一下并处理不存在的情况。

  • 我将这个 lamda: () -&gt; LiveData&lt;Resource&lt;List&lt;T&gt;&gt; 传递给我的活动,但它抛出 NotSerializableException。您能否详细说明我们如何处理这种情况? (2认同)

Jav*_*tón 6

也许为时已晚,但是:

你有没有试过把val callback里面的同伴对象?解决方案可能类似于:

companion object {
    private lateinit var callback 

    fun newInstance(tryAgainFunction: () -> Unit): TimeOutHandlerFragment {
        val fragment = TimeOutHandlerFragment()
        this.callback = tryAgainFunction
        return fragment
    }
}

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    btnTryAgain.setOnClickListener { callback.invoke() }
}
Run Code Online (Sandbox Code Playgroud)

  • 但现在我遇到了一个问题,当 Fragment 的 Activity 因“NotSerializedException”进入后台时,我的回调无法“序列化”。回调示例:“(String?, List&lt;Int&gt;?) -&gt; (Unit)”和“(Boolean) -&gt; (Unit)” (2认同)