【问题标题】:Kotlin Android Button.onClickListener causing NoSuchMethodErrorKotlin Android Button.onClickListener 导致 NoSuchMethodError
【发布时间】:2017-11-04 07:48:20
【问题描述】:

我想我发现了使用 kotlin for android 的一个怪癖,或者我对语法的理解存在一些差距。

尝试为按钮设置onClickListener 会抛出NoSuchMethodError

这是错误代码

button.setOnClickListener(Button.OnClickListener {
            fun onClick(view: View){
                val intent : Intent = Intent(this,DetailActivity::class.java)
                if(obj is String) {
                    intent.putExtra("Topic", obj)
                }
                startActivity(intent)
            }
        })

这是输出的堆栈跟踪

 java.lang.NoSuchMethodError: No static method OnClickListener(Lkotlin/jvm/functions/Function1;)Landroid/view/View$OnClickListener; in class Landroid/widget/Button; or its super classes (declaration of 'android.widget.Button' appears in /system/framework/framework.jar:classes2.dex)

有人知道怎么回事吗?

【问题讨论】:

    标签: android exception kotlin


    【解决方案1】:

    有趣的是,我没有收到该错误,您的代码为我编译。但是,由于不同的原因,它不会起作用:您在 {} 中传递了一个 lambda 作为侦听器,这意味着它的内容将在单击事件发生时执行。虽然没有代码可以在其中运行,但您只是定义了一个名为 onClicklocal function,它永远不会被调用。

    button.setOnClickListener(Button.OnClickListener {
        fun onClick(view: View){
            ...
        }
    
        Log.d("TAG", "hi") // this is the code that would be executed on click events
    })
    

    有两种方法可以修正你的语法:

    首先,您可以使用object expression 创建侦听器,这与您编写的非常接近,并且与经典的Java 解决方案类似,它显式创建了一个匿名类(注意OnClickListener接口其实在View类下):

    button.setOnClickListener(object: View.OnClickListener {
        override fun onClick(v: View?) {
            val intent = ...
        }
    })
    

    或者,您可以使用更短、更类似于 Kotlin 的语法,当您尝试使用以前的长格式时,IDE 会建议您使用 SAM conversion

    button.setOnClickListener {
        val intent = ...
    }
    

    此解决方案使用 lambda,就像您的初始代码一样,它只是没有显式命名它转换为的接口,并删除了不需要单个 lambda 参数的 ()

    【讨论】:

      【解决方案2】:

      试试

      button.setOnClickListener {
          // Handler code here
      }
      

      【讨论】:

        【解决方案3】:

        你可以试试:

        // case 1
        button?.setOnClickListener { view -> 
           // handler here
        }
        
        // case 2
        button?.setOnClickListener {
           // you can use keyword 'it' for use member view
           // handler here
        }
        

        【讨论】: