Kotlin 中的 lambda 是否始终保留对其创建对象的引用?

1 lambda android closures memory-leaks kotlin

我有一个关于 kotlin lambda 和对this. 让我们看一下这段代码:

class MyViewModel: ViewModel {
    val eventFlow = mutableSharedFlow<Unit>()
}

class MyFragment: Fragment() {
    val viewModel = MyViewModel()

    val lambda_1: (Unit) -> Unit = { Log.v("TAG", "Event happened") }
    val lambda_2: (Unit) -> Unit = { processEvent() }

    fun processEvent() {
        //do smth
    }
    
    override fun onCreate(bundle: Bundle?) {
        lifecycleScope.launchWhenStarted {
            viewModel.eventFlow.collect(lambda_1)
        }
        lifecycleScope.launchWhenStarted {
            viewModel.eventFlow.collect(lambda_2)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请告诉我我的说法是否正确:

  1. lambda_1不调用 的任何方法或变量MyFragment,因此它不保存对MyFragment对象的引用。
  2. lambda_2确实从 调用方法MyFragment,因此它确实持有对对象的引用MyFrgament
  3. 如果第二个是正确的,那么当使用这样的 lambda 时,我们违反了 MVVM 的要点之一(“ViewModel 不能引用 View”),因为存在一个引用链viewModel-> eventFlow-> lambda_2-> MyFragment

尝试读取字节码但无法从中找出答案。

bro*_*oot 5

1. 是的,这是正确的。lambda_1不需要对 的引用MyFragment,因此它不会保留一个。事实上,由于 可能lambda_1是完全静态的,Kotlin 编译器会创建一个单例并为 的所有实例重用同一个实例MyFragment

2.这也是正确的。lambda_2需要引用MyFragment,因此它保留了一个。在这种特定情况下,它的工作方式与内部类类似,因此当MyFragment实例化 lambda 时,它会通过构造函数传递对其自身的引用。一般来说,它是不同的,因为 lambda 保存对其需要的任何对象的引用,无论它是否是“外部”类。

3. 说实话,我对 MVVM 不是很熟悉,但我认为它的限制与一般的良好实践相同。

A)。如果您关注的是应用程序架构和关注点分离,因此较低层不应调用较高层,那么这种情况并不违反此规则。View只在viewmodel中注册一个事件,但viewmodel仍然不直接引用view,也不知道它们。

b). 如果您担心 的实例MyFragment被泄漏,它无法被垃圾收集,那么在这种特定情况下这不是问题。收集流量时MyFragment使用。lifecycleScope当片段被销毁时,它会lifecycleScope取消所有启动的协程,流收集器也会被取消,因此不再需要 lambda 并且可以进行垃圾收集。