有没有办法观察何时调用另一个 class 的方法?

Is there a way to observe when a method from another class is called?

我想要一个具有不同按钮的自定义键盘 class。这个 class 将在每个按钮被调用时实现 onClick 监听器,但我想要另一个 class 来处理这个事件。例如:

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

如何解决这个问题?

  1. 在键盘 class
  2. 中创建属性 clickListener
  3. 为此属性创建setter
  4. Keyboard 的 onCLick 方法中调用 clickListener?.onClick(buttonClicked) 其中 buttonClicked 是键盘上被点击的按钮
  5. 在您的 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
        })
    }
}

如果您的 objective 是在 MainActivityKeyboard 之间进行通信,那么回调就可以了。你可以这样实现它:

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 variable can only hold one listener), 可以看到这个问题here.

如果这对你的实施来说没问题,那就去做吧(它被称为 Command Pattern**). If it's not, then you need to implement the 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 playground.

中为 observable 做了一个简单的例子

** 嗯,不完全是,它是它的简化版本,因为命令模式是使用 接口 class 实现的表示"command/callback",class可以存储任意状态,函数指针不能。