【问题标题】:Unresolved reference inside anonymous Kotlin listener匿名 Kotlin 侦听器中未解析的引用
【发布时间】:2016-01-27 23:04:45
【问题描述】:

我有下面的代码。它是科特林。知道为什么来自textToSpeech.setLanguage(Locale.UK)textToSpeech 告诉textToSpeech 没有解决参考吗?

val textToSpeech = TextToSpeech(
            applicationContext,
            object : TextToSpeech.OnInitListener {
                override fun onInit(status: Int) {
                    if (status == TextToSpeech.SUCCESS) {
                        textToSpeech.setLanguage(Locale.UK)
                    }
                }

            })

一开始我以为是idea kotlin插件的bug,但是好像真的编译不出来

【问题讨论】:

    标签: android text-to-speech kotlin


    【解决方案1】:

    Kotlin 强化了变量初始化策略,现在禁止在其初始化程序中引用变量,即使在 lambda 和对象表达式中也是如此,这似乎是合理的:想象在变量赋值之前立即调用 lambda。

    对于您的情况,我可以建议在这个非常麻烦的结构中使用 object expression 作为解决方法:

    val textToSpeech = object {
        val value: TextToSpeech get() = inner
        private val inner = TextToSpeech(
                applicationContext,
                { value.setLanguage(Locale.UK) }
        )
    }.value
    

    这将初始化一个内部带有inner 的匿名对象,该对象可以通过value 属性接受。请注意,inner 初始化程序使用 value 属性。然后value被提取出来就可以使用了。

    但请记住,这个技巧是不安全的:在运行时,在分配inner 之前使用value(例如在TextToSpeech 构造函数中)将抛出NullPointerException

    另外,我已经用 lambda 替换了 OnInitListener,使用 SAM conversion 来缩短,但对象表达式仍然可以在那里使用。


    UPD: 请查看this question,了解我为推广这种方法所做的努力。使用它,您可以编写
    val textToSpeech = selfReference {
        TextToSpeech(
            applicationContext,
            { self.setLanguage(Locale.UK) }
        )
    }
    

    请参阅sources on Github

    【讨论】:

      【解决方案2】:

      这是解决该问题的一种非常易读且清晰的方法。首先你应该定义这个:

      fun <T> selfReferenced(initializer: () -> T) = initializer.invoke()
      operator fun<T> T.getValue(any: Any?, property: KProperty<*>) = this
      

      以后使用

      val valueName: ValueType by selfReferenced{
          //here you can create and use the valueName object
      }
      

      以你的问题为例,你可以这样做:

      val textToSpeech:TextToSpeech by selfReferenced {
      TextToSpeech(
              applicationContext,
              TextToSpeech.OnInitListener { status ->
                  if (status == TextToSpeech.SUCCESS) {
                      textToSpeech.setLanguage(Locale.UK)
                  }
              })
          }
      

      在 selfReferenced 块中,您可以不受限制地使用外部对象。唯一需要注意的是显式声明类型以避免递归类型检查问题。

      【讨论】:

        猜你喜欢
        • 2012-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-07
        • 1970-01-01
        • 1970-01-01
        • 2016-12-06
        相关资源
        最近更新 更多