Есть ли способ наблюдать, когда вызывается метод из другого класса? - PullRequest
0 голосов
/ 28 марта 2020

Я хочу иметь пользовательский класс клавиатуры, который имеет разные кнопки. Этот класс будет реализовывать прослушиватель onClick при вызове каждой кнопки, но я хочу, чтобы другой класс обрабатывал это событие. Например:

class Keyboard {
   Button A
   Button B
   ...
   fun onClick() {
      // forward this action to the class that contains me
   }
}

class MainActivity {
   val keyboard = Keyboard()
   keyboard.onClickListener {
      // handle the click events
   }
}

Как к этому подойти?

Ответы [ 2 ]

1 голос
/ 28 марта 2020

Если ваша цель - установить связь между MainActivity и Keyboard, тогда обратный вызов будет работать нормально. Вы можете реализовать это так:

typealias KeyboardCallback = (Button) -> Unit

// Do not recommend doing this, it's for the example only
// It's probably better parsing the keyboard input as Char or Int
enum class Button {
  A, B, C, D
}

class Keyboard {

   private var callback : KeyboardCallback? = null

   fun onKeyPressedListener(listener: KeyboardCallback) {
     callback = listener
   }

   fun onClick(button: Button) {
      // forward this action to the class that contains me
      callback?.invoke(button)
   }
}

class MainActivity {
   val keyboard = Keyboard()
   keyboard.onKeyPressedListener { key: Button ->
      // parse buttons here
   }

   // Somewhere else (Will call the callback)
   keyboard.onClick(Button.A)
}

Но если вам нужно слушать Клавиатуру из нескольких мест, то эта реализация не будет работать, потому что как только вы зарегистрируете второй обратный вызов, первый становится устаревшим (вы теряете ссылку на него, поскольку переменная callback может содержать только одного слушателя), вы можете увидеть эту проблему здесь .

Если это нормально для вашей реализации, тогда выполните это (это известно как Образец Команды **). Если это не так, то вам нужно реализовать Observable / Observer Pattern , который был бы больше похож на это:

typealias KeyboardCallback = (Button) -> Unit

// Do not recommend doing this, it's for the example only
// It's probably better parsing the keyboard input as Char
enum class Button {
  A, B, C, D
}

class Keyboard {

   private val listeners = ArrayList<KeyboardCallback>()

   fun onKeyPressedListener(listener: KeyboardCallback) {
     callback.add(listener)
   }

   fun onClick(button: Button) {
      // forward this action to the class that contains me
      for (callback in listeners) {
          callback(button)
      }
   }
}

class MainActivity {
   val keyboard = Keyboard()
   keyboard.onKeyPressedListener { key: Button ->
      // parse buttons here
   }

   keyboard.onKeyPressedListener { another: Button ->
       // added another listener
   }

   // Somewhere else (Will call the callback)
   keyboard.onClick(Button.A)
}

Я сделал простой пример для наблюдаемого в этом kotlin детская площадка .

** Ну, не совсем, это упрощенная версия, поскольку шаблон команды реализован с использованием интерфейса и класс для представления «команда / обратный вызов», и этот класс может хранить произвольное состояние, которое не может указатель функции.

0 голосов
/ 28 марта 2020
  1. Создать атрибут clickListener в классе клавиатуры
  2. Создать установщик для этого атрибута
  3. В вашем методе onCLick в Keyboard просто вызвать clickListener?.onClick(buttonClicked), где buttonClicked - кнопка на клавиатуре, на которую нажали
  4. В вашем MainActivity установите прослушиватель и обработчик clickEvent

Пример:

class Keyboard {
    private var clickListener: View.OnClickListener? = null

    fun setListener(listener: View.OnClickListener) {
        clickListener = listener
    }

    fun onClick() {
        clickListener?.onClick(buttonClicked) // pass button which was clicked
    }
}

class MainActivity {
    private val keyboard = Keyboard()

    init {
        keyboard.setListener(View.OnClickListener {
            //do something
            //it -> button which was clicked
        })
    }
}
...