Kotlin recommended way of unregistering a listener

2019-07-11 18:35发布

问题:

So i have an interactor which performs an insert operation with Realm and then notifies that the insertion is completed with a RealChangeListener. It is something like this:

fun insertCar(item: Car) {
        realm.doInTransaction {
            val car = Car(...)
            val copy = copyToRealm(car)
            copy.addChangeListener(...)
        }
    }

I can do it this way:

fun insertCar(item: Car, listener: RealmChangeListener<Car>) {
            realm.doInTransaction {
                val car = Car(...)
                val copy = copyToRealm(car)
                copy.addChangeListener(listener)
            }
        }

And access like this:

realmInteractor.insertCar(item, RealmChangeListener {
   // do something here
})

But then i have no way of removing this listener

realmInteractor.insertCar(item, RealmChangeListener {
   // do something here
   it.removeChangeListener(this)
})

this will point to the class its located not the actual listener

I can also do this:

fun insertCar(item: Car, doAfterChange (Car) -> Unit) {
                realm.doInTransaction {
                    val car = Car(...)
                    val copy = copyToRealm(car)
                    copy.addChangeListener(RealmChangeListener{
                    doAfterChange()
                    })
                }
            }

But then i have a SAM inside another SAM (too overkill imo)

I can do it like this:

fun insertCar(item: Car, listener: RealmChangeListener<Car>) {
                realm.doInTransaction {
                    val car = Car(...)
                    val copy = copyToRealm(car)
                    copy.addChangeListener(listener)
                }
            }

realmInteractor.insertCar(item, object : RealmChangeListener<Car> {
                        override fun onChange(element: Car?) {
                            ...
                            element?.removeChangeListener(this)
                        }
                    })

Which works but it is too verbose.

So how do you deal with this and what is considered the best approach?

回答1:

You can create a generic method to perform a run-once listener. Something along the lines of:

fun <T> createInRealm(objectFactory: () -> T, changeListener: (T) -> Unit) {
    realm.doInTransaction {
         val obj = objectFactory()
         val copy = copyToRealm(obj)
         copy.addChangeListener(object : RealmChangeListener<T> {
             override fun onChange(element: T) {
                 changeListener()
                 element.removeChangeListener(this)
             }
         }
    }
}