как лениво инициализировать UI-компонент - PullRequest
2 голосов
/ 09 июля 2019

Приведу следующий пример: как я могу сделать ленивую инициализацию TextView. Я попытался выполнить инициализацию с помощью lateinit, и это сработало, но это невозможно сделать с помощью функции lazy lampda

Активность

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

    onCreate(...) {...}

Ответы [ 4 ]

1 голос
/ 09 июля 2019

Вместо использования var вы должны использовать val

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

Кроме того, если установлен плагин kotlin android , вам также не нужно звонить 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{
...
}
0 голосов
/ 09 июля 2019
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)

}

источник

0 голосов
/ 09 июля 2019

Вы не можете использовать lazy с var.Вы можете использовать var lateinit mTextViewResult : TextView и mTextViewResult = findViewById (...) в onCreate или вы можете использовать synthetics для доступа к TextView по его идентификатору, определенному в xml.

0 голосов
/ 09 июля 2019

Я предлагаю вам использовать Библиотека привязки данных для упрощения инициализации / использования элементов макета.

Выполните следующие действия:

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 !
    }
}
...