androidkotlinrx-java2viper-architecture

handle onKeyDown using RxAndroid


I am using https://github.com/mkoslacz/Moviper for my app for Android Tv Box. There is only one activity with multiple child fragments. I want to propagate the onKeyDown to child fragments only if event is not already handled. It was easy to do without using RxJava. I could return a boolean to tell that event is already handled or not. Is there a way I can handle it using RxJava? I am using Kotlin as source language. Here is something I am trying to do.

class MainActivity : ViperAiPassiveActivity<HomeContract.View>(), HomeContract.View {

private val keyPressSubject = BehaviorSubject.create<KeyEvent>()
private lateinit var predicate: (KeyEvent) -> Boolean

override fun keyPresses(predicate: (KeyEvent) -> Boolean): Observable<KeyEvent> {
    this.predicate = predicate
    return keyPressSubject
}


override fun createPresenter() = HomePresenter()

override fun getLayoutId(): Int {
    return R.layout.activity_main
}

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    event?.run {
        if (predicate(event)) {
            keyPressSubject.onNext(event)
            return true
        }
    }
    return super.onKeyDown(keyCode, event)
}
}

Solution

  • I ended up creating my own Event Handler (although its not using RxJava but it does the job in my case)

    object KeyEventManager {
    
    private val handlers: MutableMap<Int, (KeyEvent?) -> Boolean> = ArrayMap()
    
    fun register(handler: (KeyEvent?) -> Boolean): Int {
        val id = (handlers.keys.max() ?: 0) + 1
        handlers.put(id, handler)
        return id
    }
    
    fun unregister(id: Int) {
        handlers.remove(id)
    }
    
    fun postEvent(event: KeyEvent?): Boolean {
        for (key in handlers.keys) {
            handlers.get(key)?.run {
                if (invoke(event)) {
                    return true
                }
            }
        }
        return false
    }
    
    }