匿名Kotlin监听器内未解决的引用

时间:2016-01-27 23:04:46

标签: android text-to-speech kotlin

我有以下代码。这是Kotlin。知道为什么来自textToSpeech的{​​{1}}告诉textToSpeech.setLanguage(Locale.UK)没有解析参考?

textToSpeech

起初我认为它是一个Idea kotlin插件错误,但似乎它实际上无法编译

2 个答案:

答案 0 :(得分:8)

Kotlin已经强化了变量初始化策略,现在禁止在其初始化程序中引用变量,即使在lambdas和对象表达式中也是如此,这似乎是合理的:想象一下在变量赋值之前立即调用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并可以使用。

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

此外,我已使用SAM conversionOnInitListener替换为lambda,但是仍然可以在那里使用对象表达式。

<小时/> UPD:检查this question我是否努力推广这种方法。使用它,你可以写

val textToSpeech = selfReference {
    TextToSpeech(
        applicationContext,
        { self.setLanguage(Locale.UK) }
    )
}

请参阅sources on Github

答案 1 :(得分:0)

这是解决该问题的一种非常容易理解的清晰方法。首先,您应该定义以下内容:

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块内,您可以不受限制地使用外部对象。您唯一需要注意的是明确声明类型,以避免递归类型检查问题。