Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

android - Unresolved reference inside anonymous Kotlin listener

I have the code below. It is Kotlin. Any idea why textToSpeech from textToSpeech.setLanguage(Locale.UK) is telling that there is no reference resolved for textToSpeech?

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

            })

At first I assumed it is an Idea kotlin plugin bug, but it seems that it actually can't be compiled

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Kotlin has hardened the variables initialization policy, and it's now prohibited to reference the variable inside its initializer, even in lambdas and object expressions, which seems reasonable: imagine that a lambda is called immediately before the variable assignment.

For your case, I can suggest as a workaround using an object expression in this quite cumbersome construct:

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

This will initialize an anonymous object with inner inside that is acceptable through value property. Note that the inner initializer uses value property. Then the value is extracted and can be used.

But please keep in mind that this trick is unsafe: in runtime, using value before inner is assigned (e.g. in TextToSpeech constructor) will throw NullPointerException.

Also, I've replaced the OnInitListener with a lambda using SAM conversion to be short, but object expression can still be used there.


UPD: check this question for my effort to generalize this approach. Using it, you can write
val textToSpeech = selfReference {
    TextToSpeech(
        applicationContext,
        { self.setLanguage(Locale.UK) }
    )
}

See the sources on Github.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...