Multiple overrides passed to function


#1

I have the following method in Java for monitoring iBeacons.
I am new to Kotlin and wondering how i represent the multiple overridden methods that the listener expects?

    beaconManager.setMonitoringListener(new BeaconManager.BeaconMonitoringListener() {
        @Override
        public void onEnteredRegion(BeaconRegion region, List<Beacon> beacons) {
            try {
                emitMonitoringEvent(region.getIdentifier(), "enter");
            } catch (JSONException jse) {
                jse.printStackTrace();
            }
        }
        @Override
        public void onExitedRegion(BeaconRegion region) {
            try {
                emitMonitoringEvent(region.getIdentifier(), "exit");
            } catch (JSONException jse) {
                jse.printStackTrace();
            }
        }
    });

#2

There are some approaches. If you want the version closest to Java you would just write it as an anonymous object expression:

beaconManager.monitoringListener = object : BeaconManager.BeaconMonitoringListener {
	override fun onEnteredRegion(region: BeaconRegion, beacons: List<Beacon>) {
		emitMonitoringEvent(region.identifier, "enter")
	}
	
	override fun onExitedRegion(region: BeaconRegion) {
		emitMonitoringEvent(region.identifier, "exit")
	}
}

#3

Thanks that works well
Is there a way to do this with lambdas also?


#4

not straight out of the box.
you can do this with an additional class.

for the examples I’m using type alias, which renames the lambda into a simple name

I’m using typealias (for renaming the lambda’s to an easier to unserstand name
and apply (executes things on an object and then returns itself).

both functions are required

When both the functions must be overridden, you can create the following class:

typealias OnEnter = (region: BeaconRegion, beacons: List<Beacon>)->Unit
typealias OnExit = (region: BeaconRegion)->Unit

class ComposableMonitoringListener(
    public var onEnter: OnEnter,
    public var onExit: OnExit
)BeaconMonitoringListener{
    override fun onEnteredRegion(region: BeaconRegion, beacons: List<Beacon>) = onEnter(region, beacons)
    override fun onExitedRegion(region: BeaconRegion) = onExit(region)
}

which you can call like:

 ComposableMonitoringListener(
     onEnter = {region, beacons-> ...},
     onExit = {region -> }
 )

one functions is required

typealias OnEnter = (region: BeaconRegion, beacons: List<Beacon>)->Unit
typealias OnExit = (region: BeaconRegion)->Unit

class ComposableMonitoringListener(
        public var onEnter: OnEnter,
): BeaconMonitoringListener{
   private var onExit: OnExit? = null
   fun onExitedRegion(onExit: OnExit?) = this.apply{
       this.onExit = onExit
   }

    override fun onEnteredRegion(region: BeaconRegion, beacons: List<Beacon>) = onEnter(region, beacons)
    
    override fun onExitedRegion(region: BeaconRegion){
        onExit?.invoke(region)
    }
}

which you can call like:

 ComposableMonitoringListener(
     onEnter = {region, beacons-> ...},
 ).onExitedRegionon{region -> }

or even

 ComposableMonitoringListener{region, beacons-> ...}
        .onExitedRegionon{region -> }

both functions are optional

typealias OnEnter = (region: BeaconRegion, beacons: List<Beacon>)->Unit
typealias OnExit = (region: BeaconRegion)->Unit

class ComposableMonitoringListener: BeaconMonitoringListener{
   private var onExit: OnExit? = nul
   private var onEnter: OnEnter? = null

   fun onExitedRegion(onExit: OnExit?) = this.apply{
       this.onExit = onExit
   }

   fun onEnteredRegion(onEnter: OnEnter?) = this.apply{
       this.onEnter = onEnter
   }

    override fun onEnteredRegion(region: BeaconRegion, beacons: List<Beacon>) { onEnter?.invoke(region, beacons) }   
    override fun onExitedRegion(region: BeaconRegion) { onExit?.invoke(region) }
}

which you call like

ComposableMonitoringListener()
    .onEnteredRegion{region, beacons-> ...}
    .onExitedRegionon{region -> }

remark

Of course, if an function is optional, you can also ask it as an optional constructor argument.


#5

From Kotlin 1.2 you can write it like this: (my favourite method)

inline fun BeaconManager.setMonitoringListeners(
	crossinline onEnteredRegion: (region: BeaconRegion, beacons: List<Beacon>) -> Unit = {},
	crossinline onExitedRegion: (region: BeaconRegion) -> Unit = {}
) {
	this.monitoringListener = object : BeaconManager.BeaconMonitoringListener {
		override fun onEnteredRegion(region: BeaconRegion, beacons: List<Beacon>) {
			onEnteredRegion(region, beacons)
		}
		
		override fun onExitedRegion(region: BeaconRegion) {
			onExitedRegion(region)
		}
	}
}

beaconManager.setMonitoringListeners(
	onEnteredRegion = { region, _ -> emitMonitoringEvent(region.identifier, "enter") },
	onExitedRegion = { region -> emitMonitoringEvent(region.identifier, "exit") }
)