android – Java中的内存泄漏,但不是Kotlin(相同的代码库)…为什么?

前端之家收集整理的这篇文章主要介绍了android – Java中的内存泄漏,但不是Kotlin(相同的代码库)…为什么?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
参见英文答案 > Kotlin : safe lambdas (no memory leak)?2个
我在活动中有一段简单的代码……
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();
    }
}

如果活动终止,将会有内存泄漏(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).因此,如果动画在不再需要活动时继续运行,则侦听器会持续保持对活动的引用,从而防止对其进行垃圾回收.

科特林试图在这里变得更聪明.它看到传递给ValueAnimator的lambda不引用外部作用域中的任何对象(即MainActivity),因此它创建了一个单独的AnimatorUpdateListener实例,只要你[重新]启动动画,它就会被重用.并且此实例没有对外部作用域的任何隐式引用.

旁注:如果将对外部作用域中某个对象的引用添加到lambda,Kotlin将生成每次动画重新启动时创建更新侦听器的新实例的代码,这些实例将保持隐式对MainActivity的引用(为了访问您决定在lambda中使用的对象所必需的).

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

猜你在找的Android相关文章