Каков наилучший способ объявить компонент UI в Android с Kotlin?

Я пытаюсь создать приложение для Android с помощью Kotlin в первый раз.

Я хочу объявить некоторые кнопки вне метода OnCreate, и я могу их инициализировать только внутри этой функции с помощью findViewById.

Могу ли я объявить простой и чистый код, например, в java?

private Button btnProceed;

Потому что при преобразовании его в Kotlin это выглядит так:

private var btnProceed: Button? = null

И тогда, когда нужно инициализировать функцию OnClick, нужно добавить! знак:

btnProceed!!.setOnClickListener

Каков правильный и самый чистый способ?

Ответ 1

Это хороший прецедент для lateinit. Маркировка свойства lateinit позволяет сделать его недействительным, но не назначать ему значение в момент вызова конструктора Activity. Это там точно для таких классов, как "Действия", когда инициализация происходит в отдельном методе инициализации, позже запускаемого конструктора (в данном случае onCreate).

private lateinit var btnProceed: Button

Если свойство считывается до того, как ему присвоено реальное значение, он будет генерировать исключение во время выполнения - используя lateinit, вы берете на себя ответственность за его инициализацию перед тем, как вы впервые получите доступ к ней.


В противном случае, если вы хотите, чтобы компилятор гарантировал вам безопасный доступ, вы можете сделать значение Button нулевым, как это делает конвертер по умолчанию. Вместо небезопасного !!, который часто использует конвертер, вы должны использовать оператор безопасного вызова, в котором вы получаете доступ к свойству:

btnProceed?.setOnClickListener { ... }

Это приведет к регулярному вызову, если btnProceed является ненулевым значением и ничего не делает.


В заключение вы можете проверить Kotlin Android Extensions, что избавляет от необходимости создавать свойства для вашего View вообще, если он работает для вашего проекта.


Последнее редактирование (на данный момент): вы также должны посмотреть на использование lazy, как описано в other answers. Быть ленивым - это круто.

Ответ 2

Вместо использования lateinit вы также можете сделать ленивую инициализацию:

private val button by lazy {
    findViewById(R.id.button) as Button
}

При первом обращении к свойству button он будет выполнять блок один раз и использовать результат для будущих вызовов. Например, в onCreate вы можете напрямую получить к нему доступ:

fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(bundle)
  setContentView(R.layout.my_view)

  button.setOnClickListener { ... }
}

Ответ 3

Вы можете сделать это с помощью lateinit, поскольку @zsmb13 предлагает, но это имеет тот недостаток, что ваши представления будут переменными, а не final. Если вы хотите, чтобы они были окончательными, вы можете использовать lazy делегирование свойств

Используя lazy, вы можете объявить, как значение будет инициализировано при первом попытке получить к нему доступ, объявив

private val btnProceed: Button by lazy {
    findViewById(R.id.yourID)
}

Всякий раз, когда вы получаете доступ к btnProceed, вы будете загружать свою активность (этот пример предполагает, что вы используете активность), чтобы вы могли использовать этот метод