SpkingR
SpkingR

Reputation: 983

How to unsubscribe events in TornadoFX?

In TornadoFX I want to unsubscribe a custom event so that the receiver will never handle the unnecessary events again, and maybe avoid something like memory leaks, however, when I use the unsubscribe<MyEvent> method in my code it doesn't work at all. Here is the part of my code:

object MyEventObj: FXEvent(EventBus.RunOn.BackgroundThread)
class MyEventBus(val personlist:List<PersonOld>): FXEvent()
class MyController: Controller()
{
    init
    {
        subscribe<MyEventObj> {
            unsubscribe<MyEventObj> { 
                println("Unsubscribe event!") //unsubscrib event and make sure the next code just runs once, but never works!
            }
            println("Event has received!")
            val items = listOf(PersonOld("Name A", 20), PersonOld("Name B", 25))
            fire(MyEventBus(items))
        }
    }
}

So, what is the problem? And how to use unsubscribe in TornadoFX? Thanks for help me in advance!

Upvotes: 1

Views: 534

Answers (1)

Edvin Syse
Edvin Syse

Reputation: 7297

The unsubscribe function takes the event listener as it's only parameter. To be able to unsubscribe, you therefore need to save the listener as a member val so you can reference it. To make matters more interesting, you cannot reference this inside the listener itself, so you need to call out to another function to be able to unsubscribe successfully. Here is a complete example:

object MyEvent : FXEvent()

class MyView : View() {
    override val root = stackpane {
        paddingAll = 100
        button("Fire!") {
            setOnAction {
                fire(MyEvent)
            }
        }
    }

    val myListener: (MyEvent) -> Unit = {
        alert(Alert.AlertType.INFORMATION, "Event received!", "This message should only appear once.")
        stopListening()
    }

    init {
        subscribe(myListener)
    }

    fun stopListening() = unsubscribe(myListener)

}

If it was possible to reference the listener from within itself we could have added an unsubscribe() call directly inside the listener, but that's not possible, at least not with Kotlin 1.0.

EDIT: We just added a times = n parameter to subscribe so you don't need to deal with unregistration yourself. By default your event listener will be triggered every time the event fires, but by passing 1, you can unregistrer automatically after the first time. With this new feature, coming in TornadoFX 1.6.3, you can simply do this instead:

class MyView : View() {
    override val root = stackpane {
        paddingAll = 100
        button("Fire!") {
            setOnAction {
                fire(MyEvent)
            }
        }
    }

    init {
         subscribe<MyEvent>(times = 1) {
            alert(Alert.AlertType.INFORMATION, "Event received!", "This message should only appear once.")
        }
    }

}

EDIT2: TornadoFX 1.6.3 will also introduce an EventContext which the trigger operates on, so you will be able to do unsubscribe() inside the event listener from the next version. Then you can do this as an alternative to the times parameter:

subscribe<MyEvent> {
    alert(Alert.AlertType.INFORMATION, "Event received!", "This message should only appear once.")
    unsubscribe()
}

Upvotes: 2

Related Questions