'How can I passs a method except parameter in Kotlin?

I hope to pass a method which implement MediaRecorder.OnInfoListener.

At present I use Code A to pass the method which implement MediaRecorder.OnInfoListener.

Is there any other way to do it? maybe just like Code B.

Code A

class HomeViewModel(...) : AndroidViewModel(mApplication) {

    fun startRecord() {
        startRecord(savedfilename){
             mr, what, extra ->
                 if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                     stopRecord()
                 }            
        }

    }

}


class RecordService : Service() {  

    fun startRecord(filename:String, mOnInfoListener: MediaRecorder.OnInfoListener){
       mRecorder = MediaRecorder()
        mRecorder?.let {    
            with(it) {                  
                setOnInfoListener(mOnInfoListener)    
            }
        }
    }    
}

Code B

class HomeViewModel(...) : AndroidViewModel(mApplication) {

{
    //I save  mOnInfoListener to memory ?   
    val mOnInfoListener = object: MediaRecorder.OnInfoListener{
        mr, what, extra ->
           if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
              stopRecord()
          }
    }

    fun startRecord() {
        startRecord(savedfilename)    
    }

}


class RecordService : Service() {  

    fun startRecord(filename:String){
       mRecorder = MediaRecorder()
        mRecorder?.let {    
            with(it) {
                setOnInfoListener(mOnInfoListener)  //  I get mOnInfoListener from memory ?    
            }
        }
    }    
}


Solution 1:[1]

The Code A looks good in terms of passing a lambda as parameter. But I would make a couple of improvements.

I would encapsulate the work with MediaRecorder in one class, e.g. RecordService, HomeViewModel doesn't need to know anything about what tools RecordService uses to make records. And if you need to react on recorder's events you can create an additional interface for that. The sample code with all interfaces and events will look like the following:

sealed interface Event
object MaxDurationReachedEvent : Event
//... create another events if need

interface RecordServiceEventListener {
    fun onRecordEvent(event: Event)
}

interface RecordService {
    fun startRecord(filename: String)
    fun registerEventListener(listener: RecordServiceEventListener)
    fun unregisterEventListener(listener: RecordServiceEventListener)

}

class RecordServiceImpl : Service(), RecordService {

    private var recorder: MediaRecorder? = null
    private var eventListeners: MutableList<RecordServiceEventListener> = mutableListOf()

    override fun startRecord(filename: String) {
        recorder = MediaRecorder()
        recorder?.setOnInfoListener { mr, what, extra ->
            if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                eventListeners.forEach { it.onRecordEvent(MaxDurationReachedEvent) }
            }
        }
    }

    override fun registerEventListener(listener: RecordServiceEventListener) {
        eventListeners.add(listener)
    }

    override fun unregisterEventListener(listener: RecordServiceEventListener) {
        eventListeners.remove(listener)
    }
}

class HomeViewModel(private val recordService: RecordService) : ViewModel(), RecordServiceEventListener {

    init {
        recordService.registerEventListener(this)
    }

    override fun onCleared() {
        recordService.unregisterEventListener(this)
    }

    fun startRecord() {
        recordService.startRecord(savedFilename)
    }

    override fun onRecordEvent(event: Event) {
        when (event) {
            MaxDurationReachedEvent -> { ... /* Do something */ }
        }
    }
}

It is better to work with interfaces rather than with concrete implementations. Also I wouldn't suggest to use m prefix when naming variables, it is a style of Java language, not Kotlin.

P.S. Flow can be used to emit events of a recorder instead of RecordServiceEventListener, but this is another story :)

Solution 2:[2]

Here you go:

class HomeViewModel(...) : AndroidViewModel(mApplication) {
    //I save  mOnInfoListener to memory ?
    val mOnInfoListener = object : MediaRecorder.OnInfoListener {
        override fun onInfo(mr: MediaRecorder, what: Int, extra: Int) {
            if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                stopRecord()
            }
        }
    }


    fun startRecord() {
        startRecord(savedfilename)
    }

}


class RecordService(private val mOnInfoListener: MediaRecorder.OnInfoListener) : Service() {

    fun startRecord(filename: String) {
        val mRecorder = MediaRecorder()
        mRecorder.setOnInfoListener(mOnInfoListener)  //  I get mOnInfoListener from memory ?
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Kemal Cengiz