Convert the callback function to Flow

I. Introduction

In kotlin, the language has structured the program to improve readability, and also provides conversion operations for the old program logic. Here is a record of how to convert the callback into a Flow stream to optimize the program structure

2. Code example

1、callbackFlow

callbackFlowThe usage is demonstrated here . callbackFlowIt belongs to multiple callbacks that can be triggered repeatedly. Since the content is not used Channelfor communication, Channelrelated functions can be used.

   interface Listener{
    
    
        fun listener()
        fun end()
    }
inner class TouchModel{
    
    
        private var listener: Listener ?= null
        fun registerListener(sourceListener: Listener){
    
    
            listener = sourceListener
        }
        fun unregisterListener(){
    
    
            listener = null
        }

        fun emit(){
    
    
            listener?.listener()
        }
        fun end(){
    
    
            listener?.end()
        }
    }
   @Test
    fun test(){
    
    
        val model = TouchModel()
        runBlocking {
    
    

            val flow = flowFrom(model)

            flow.onEach {
    
    
                println("YM--->流:$it")
            }.launchIn(this)
            delay(1000)
            model.emit()
            delay(1000)
            model.emit()
            delay(1000)
            model.emit()
            delay(1000)
            println("YM--->流即将结束")
            model.end()
            delay(1000)

        }
    }
    //callbackFlow属于多次回调可以重复触发,由于内容不是使用Channel进行通信,所以可以使用Channel的相关函数
    fun flowFrom(model: TouchModel): Flow<Int> = callbackFlow {
    
    
        var count = 0
        val callback = object : Listener{
    
    
            override fun listener() {
    
    
//  为了避免阻塞,channel可以配置缓冲通道,这个暂时不知道怎么处理
//                trySend(count)//这两种方式都行
                    trySendBlocking(count)
                        .onFailure {
    
     throwable ->
                            // Downstream has been cancelled or failed, can log here
                        }
                    count++
            }

            override fun end() {
    
    
                //当执行结束后可以使用以下方式关闭channel,或者抛出异常,该参数可选,
//                channel.close(IllegalStateException("这个状态不对"))
//                close(IllegalStateException("这个状态不对"))
//                channel.close() 等同于  close()
                println("YM--->Channel关闭")
                close()
            }
        }
        model.registerListener(callback)
        //因为是冷流,所以需要使用awaitClose进行挂起阻塞
        awaitClose {
    
    
            //关闭注册
            println("YM--->解除注册")
            model.unregisterListener()
        }
    }

2、suspendCancellableCoroutine

If it is for a single callback. can be suspendCancellableCoroutineprocessed using . The sample code is as follows:

      interface Listener{
    
    
        fun listener()
        fun end()
    }

    inner class TouchModel{
    
    
        private var listener: Listener ?= null
        fun registerListener(sourceListener: Listener){
    
    
            listener = sourceListener
        }
        fun unregisterListener(){
    
    
            listener = null
        }

        fun emit(){
    
    
            listener?.listener()
        }
        fun end(){
    
    
            listener?.end()
        }
    }
       @Test
    fun test(){
    
    
              val model = TouchModel()
        runBlocking {
    
    
//            val flow = flowFrom(model)
            val job = async {
    
    
                val flow = awaitCallback(model)
                println("YM--->流:$flow")
            }
//            delay(1000)
//            model.emit() //解开注释就可以看到流发射的情况
            delay(1000)
            println("YM--->流即将结束")
            model.end()
//            job.cancel()//该流是可以撤销的,假若里面任务还没有结束,这个任务可以直接撤销
            delay(1000)
        }
    }
  suspend fun awaitCallback(model: TouchModel): Int = suspendCancellableCoroutine {
    
     continuation ->
        val callback = object : Listener {
    
     // Implementation of some callback interface
            override fun listener() {
    
    
                continuation.resume(0){
    
    //协程恢复时候使用
                    continuation.resumeWithException(it)
                }
//                continuation.resumeWithException(cause)
       println("YM---->isActive:${
      
      continuation.isActive}--->isCancel:${
      
      continuation.isCancelled}")
            }

            override fun end() {
    
    
                continuation.cancel()
            }
        }
        // Register callback with an API
        model.registerListener(callback)
        // Remove callback on cancellation
        continuation.invokeOnCancellation {
    
    
            println("YM---->挂起关闭")
            model.unregisterListener()
        }
        // At this point the coroutine is suspended by suspendCancellableCoroutine until callback fires
    }

It can be seen that the execution will be terminated directly after one execution. It should be noted that if the task is not executed, it will be carried out directly continuation.cancel(). Then continuation.invokeOnCancellationthe function will be executed. If it has already been executed, proceed again continuation.cancel(). will not execute continuation.invokeOnCancellation.

3、CompletableDeferred

But there is a problem with this, that is, it is not easy to close the resource if it is revoked. For details, please refer to the fourth article of the link.
This can also monitor and convert the callback function, as follows:

class CompletableDeferredTest {
    
    
    val response = CompletableDeferred<Int>()
    @Test
    fun test(){
    
    
        request(response)
        runBlocking {
    
    
            val result = response.await()
            println("YM---->结果:${
      
      result}")
//            response.cancel() //如果在结果返回前执行撤销,那么就会触发CompletableDeferred.invokeOnCompletion()函数
            delay(4000)
        }
    }

     fun request(rep: CompletableDeferred<Int>){
    
    

         Thread{
    
    //这里用线程而不用协程主要是想证明这个函数不需要协程环境就可以执行
             Thread.sleep(1000)//延迟两秒模拟请求
             rep.complete(2)
         }.start()
//         rep.completeExceptionally(IllegalStateException("非法状态异常"))//这个可以抛出异常
         rep.invokeOnCompletion {
    
    
             if (rep.isCancelled) {
    
    
                 println("Call cancelled")
             }
         }
    }

}

3. Reference link

  1. callbackFlow

  2. Use a more secure way to collect Android UI data flow

  3. The difference between Kotlin–suspendCancellableCoroutine and suspendCoroutine and their use - Th.one's Blog - CSDN Blog

  4. CoroutineScope - CompletableDeferred cancellation

Guess you like

Origin blog.csdn.net/Mr_Tony/article/details/126119816