与匿名内部类相比,Kotlin lambda的表现如何?

时间:2019-02-24 17:24:16

标签: android lambda kotlin onclicklistener

Android Studio建议用lambda代替匿名内部类。

titleTextView.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
        Log.d("MY_TAG", "textView clicked in anonymous inner class")
    }
})

反编译的Java代码:

var10000 = this.titleTextView;
if (this.titleTextView == null) {
    Intrinsics.throwUninitializedPropertyAccessException("titleTextView");
}

var10000.setOnClickListener((OnClickListener)(new OnClickListener() {
    public void onClick(@Nullable View v) {
        Log.d("MY_TAG", "textView clicked in anonymous inner class");
    }
}));

在使用lambda之前,为避免为每个设置了OnClickListener的视图创建新对象,最好让Activity / Fragment实现View.OnClickListener接口或使用Butterknife的{​​{1}}注释。

如下所示,lambda的性能会有何不同?

@OnClick

反编译的Java代码:

titleTextView.setOnClickListener { Log.d("MY_TAG", "textView clicked in lambda") }

在使用lambda的情况下,我在反编译代码中看不到TextView var10000 = this.titleTextView; if (this.titleTextView == null) { Intrinsics.throwUninitializedPropertyAccessException("titleTextView"); } var10000.setOnClickListener((OnClickListener)null.INSTANCE);

1 个答案:

答案 0 :(得分:3)

lambda的性能至少与创建匿名内部类一样好。

  • 如果未捕获任何引用,则编译器会将其用作优化措施所使用的任何类内的单个对象。这就是您的情况,因为侦听器的内容没有引用lambda之外的任何内容。 (null.INSTANCE试图引用此单例实例,反编译器在解决为lambda生成的类的名称时遇到了麻烦。)因此,在这种情况下,lambda的成本仅为1个对象分配。

  • 如果您的lambda确实捕获了某些东西,例如像这样:

    val random = Random().nextInt()
    titleTextView.setOnClickListener { 
        Log.d("MY_TAG", "textView clicked in lambda, random value was $random") 
    }
    

    ...,那么每当您设置侦听器时,都将不得不分配一个新实例,因为这些实例必须存储对变量的引用,每次创建变量时引用可能会有所不同。在这种情况下,您获得的对象分配与运行lambda的方法的次数一样多。请注意,如果仅在安装过程中完成此操作,如onCreate,这也将意味着也只有1个对象分配。 / p>

所以您可能会得到:

  • 如果监听器是您已经存在的类(Fragment或Activity)的方法,则分配0个额外分配。
  • 如果您使用不捕获任何内容的lambda,则需要额外分配1个。
  • 如果您使用捕获了某些内容的lambda,则需要N个额外的分配,N是您运行代码使用lambda的次数,如果仅在初始化期间,则为1。
  • 如果使用匿名内部类,则没有N个额外的分配,因为那里没有针对非捕获类的优化。同样,在很多情况下,这实际上可能是1。

即使在现有类中使用方法将意味着额外分配0,但我不会采用这种方法来提高性能-任何收益都可能完全不明显。而是选择对您而言更具可读性和可维护性的解决方案。