简体   繁体   中英

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

I want to have a custom keyboard class that has different buttons. This class will implement the onClick listener when each button is called but I want another class to handle this event. For example:

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

How to approach this?

If your objective is to communicate between the MainActivity and the Keyboard then a callback will do just fine. You could implement it like this:

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

But if you need to listen to the Keyboard from multiples places, then this implementation will not work because as soon as you register a second callback, the first one gets stale (you lose the reference to it, since the callback variable can only hold one listener), you can see this problem here .

If this is ok for your implementation, then do it (it's known as the Command Pattern **). If it's not, then you need to implement the Observable/Observer Pattern , which would be more like this:

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

I've made a simple example for the observable in this kotlin playground .

** Well, not exactly, it's a simplified version of it, since the command pattern is implemented using a interface and a class to represent the "command/callback", and that class can store arbitrary state, which the function pointer cannot.

  1. Create attribute clickListener in Keyboard class
  2. Create setter for this attribut
  3. In your onCLick method in Keyboard just call clickListener?.onClick(buttonClicked) where buttonClicked is button in keyboard which was clicked
  4. In your MainActivity set listener and handle clickEvent

Example:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM