Почему разработчики не передают аргументы непосредственно в setOnCheckedChangeListener

#android #kotlin

#Android #kotlin

Вопрос:

Я новичок в Android. Вот код:

 Switch.setOnCheckedChangeListener { _, isChecked ->
// do something}
  

Я сделал некоторое кодирование на C , поэтому я знаю, что должен вызывать его следующим образом

 variable = OnCheckedChangeListener    
Switch.setOnCheckedChangeListener**(variable)** { _, isChecked ->
        // do something}
  

Я не знаю, почему функция работает без моего ввода каких-либо аргументов.

Большое вам спасибо.

Комментарии:

1. Вы передаете аргумент. { _, isChecked -> ... } Часть является аргументом в форме лямбда-выражения.

2. Я проследил эту странную иерархию наследования. Не могли бы вы сказать мне, прав ли я. setOnCheckedChangeListener требует OnCheckedChangeListener в качестве своего параметра. OnCheckedChangeListener — это интерфейс, который на самом деле является просто функцией. В итоге вы передаете эту функцию в качестве аргумента setOnCheckedChangeListener.

3. «OnCheckedChangeListener — это интерфейс, который на самом деле является просто функцией» — не совсем, но вы близки. OnCheckedChangeListener имеет единственную абстрактную функцию в определении интерфейса. Kotlin поддерживает создание экземпляров такого интерфейса из лямбда-выражения или другого типа функции .

Ответ №1:

Если мы посмотрим на исходный код для Switch представления, setOnCheckedChangeListener() метод определяется следующим образом:

 fun setOnCheckedChangeListener(listener: CompoundButton.OnCheckedChangeListener?) {
    mOnCheckedChangeListener = listener
}
  

Он ожидает аргумент в виде интерфейса OnCheckedChangeListener , определение которого выглядит следующим образом:

 interface OnCheckedChangeListener {
    fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean)
}
  

У него есть только один метод. Интерфейс только с одним абстрактным методом называется функциональным интерфейсом или интерфейсом с одним абстрактным методом (SAM).

Для функциональных интерфейсов вы можете использовать преобразования SAM, которые помогают сделать ваш код более кратким и читаемым с помощью лямбда-выражений.

Вместо создания класса, который реализует функциональный интерфейс вручную, вы можете использовать лямбда-выражение. С помощью преобразования SAM Kotlin может преобразовать любое лямбда-выражение, сигнатура которого совпадает с сигнатурой единственного метода интерфейса, в экземпляр класса, который реализует интерфейс.

Итак, причина, по которой вам не нужно передавать экземпляр OnCheckedChangeListener , заключается в том, что из-за синтаксического сахара Kotlin позволяет вам просто определить тело метода, который описывается интерфейсом, и он создаст и передаст аргумент за кулисами.

Если бы вы хотели сделать это самостоятельно, это выглядело бы так:

 switch.setOnCheckedChangeListener(object : OnCheckedChangeListener {
    override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
        // do something
    }
})
  

Комментарии:

1. Большое вам спасибо. Это лучший ответ, потому что вы подробно рассказали о том, что на самом деле происходит под капотом с вашим последним фрагментом кода. Большинство книг для начинающих, обучающих программированию на Android, не вдаются в этот уровень детализации. Они думают, что новички все Энштейны.