如何懒惰地初始化UI组件

时间:2019-07-09 16:08:22

标签: android kotlin lazy-initialization

在belwo示例中,我该如何对TextView进行惰性初始化。 我试图通过lateinit进行初始化,但仍能正常工作,但无法通过惰性Lampda函数完成

活动

npm

4 个答案:

答案 0 :(得分:1)

您应该使用var

,而不要使用val

val mTextViewResult : TextView by lazy { findViewById(R.id.tvResult) }

还有,如果应用了kotlin android extensions插件,您也不必调用findViewById()

在应用程序级别build.gradle中添加kotlin android扩展插件

apply plugin: "com.android.application"
apply plugin: "kotlin-android"
apply plugin: "kotlin-kapt"
apply plugin: "kotlin-android-extensions" // this plugin

...

现在,您可以通过导入布局参考来使用tvResult

import kotlinx.android.synthetic.main.<layout>.*

class MainActivity : AppCompatActivity{
...
}

答案 1 :(得分:0)

我建议您使用DataBinding library来简化初始化/使用布局项目。

执行以下操作:

class YourClassActivity() {

    private var myTextView : TextView? = null    // At first, myTextView is null. Do not use it !

    private var viewModel = YourViewModel()

    override fun onCreate(...) {
        val binding = DataBindingUtil.setContentView<ActivityYourClassBinding>(this, R.layout.activity_your_class) // DataBinding will set your view
        binding.viewModel = yourViewModel

        // Init layout variables
        myTextView = binding.myTextView // If your TextView id is "my_text_view"

        /*
        ** Now you can use 'myTextView' in any of your function (not just onCreate).
        ** Just do not forget to put the nullable '?' mark after its name.
        */
        myTextView?.text = "Hello World"
        myTextView?.setOnClickListener { clear() }
    }

    private fun clear() {
        myTextView?.text = "" // You can use your variable anywhere you want !
    }
}

答案 2 :(得分:0)

您不能将lazyvar一起使用。您可以在onCreate中使用var lateinit mTextViewResult : TextView和mTextViewResult = findViewById(...),也可以使用synthetics通过XML中定义的ID访问TextView。

答案 3 :(得分:0)

public fun <V : View> Activity.bindView(id: Int)
        : ReadOnlyProperty<Activity, V> = required(id, viewFinder)

private val Activity.viewFinder: Finder<Activity>
    get() = { findViewById(it) }


private fun viewNotFound(id: Int, desc: KProperty<*>): Nothing =
    throw IllegalStateException("View ID $id for '${desc.name}' not found.")

@Suppress("UNCHECKED_CAST")
private fun <T, V : View> required(id: Int, finder: Finder<T>) =
    Lazy { t: T, desc -> t.finder(id) as V? ?: viewNotFound(id, desc) }

typealias Finder<T> = T.(Int) -> View?

// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it
private class Lazy<T, V>(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty<T, V>, LifecycleObserver {
    private object EMPTY

    private var value: Any? = EMPTY
    private var attachedToLifecycleOwner = false

    override fun getValue(thisRef: T, property: KProperty<*>): V {
        checkAddToLifecycleOwner(thisRef)
        if (value == EMPTY) {
            value = initializer(thisRef, property)
        }
        @Suppress("UNCHECKED_CAST")
        return value as V
    }

    private fun checkAddToLifecycleOwner(thisRef: T) {
        if (!attachedToLifecycleOwner && thisRef is LifecycleOwner) {
            thisRef.lifecycle.addObserver(this)
            attachedToLifecycleOwner = true
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun destroy() {
        value = EMPTY
    }
}

并像这样使用它:

class MainActivity : AppCompatActivity() {

    private val mTv: TextView by bindView(R.id.tv)

}

source