gpt4 book ai didi

android - Java 中的内存泄漏,但 Kotlin(相同代码库)中没有……为什么?

转载 作者:IT老高 更新时间:2023-10-28 13:44:22 26 4
gpt4 key购买 nike

我在一个 Activity 下面有一段简单的代码...

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {

}
});
valueAnimator.start();
}
}

如果 Activity 被终止,就会发生内存泄漏(Leak Canary 证明了这一点)。

但是,当我将此代码转换为相同的 Kotlin 代码(使用 shift-alt-command-k)时,如下所示

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
valueAnimator.repeatCount = ValueAnimator.INFINITE
valueAnimator.addUpdateListener { }
valueAnimator.start()
}
}

不再发生内存泄漏。为什么?是因为匿名类对象被转换为 Lambda 了吗?

最佳答案

这两个版本的区别很简单。

AnimatorUpdateListener 的 Java 版本包含对外部类的隐式引用(在您的情况下为 MainActivity)。因此,如果动画在不再需要 Activity 时继续运行,则监听器会继续持有对 Activity 的引用,从而防止它被垃圾回收。

Kotlin 试图在这里变得更聪明。它看到您传递给 ValueAnimator 的 lambda不引用外部范围内的任何对象(即 MainActivity),因此它创建了一个 AnimatorUpdateListener单个实例每当您[重新]启动动画时,都会重复使用它。而且这个实例没有任何对外部作用域的隐式引用。

旁注:如果您将某个对象的引用从外部作用域添加到您的 lambda,Kotlin 将生成代码,该代码会在每次动画 [re] 时创建更新监听器的新实例已启动,并且这些实例将持有对 MainActivity 的隐式引用(访问您决定在 lambda 中使用的对象所必需的)。

另一个附注:我强烈建议阅读名为“Kotlin in Action”的书,因为它包含很多关于 Kotlin 的一般有用信息,以及我对 Kotlin 编译器如何选择的解释是否将对外部作用域的隐式引用放入SAM转换后创建的对象中,来自本书。

关于android - Java 中的内存泄漏,但 Kotlin(相同代码库)中没有……为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48149902/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com