簡體   English   中英

如何在 WebSocketListener 中使用暫停 function 或 viewModelScope/lifecycleScope?

[英]How can I use suspend function or viewModelScope/lifecycleScope in WebSocketListener?

我用 WebSocketListener 實現了 WebSocket。 我想使用協程通道。 但是現在我需要在 Coroutine Scope 中調用它。 在這里,我沒有 viewModelScope 也沒有生命周期范圍。 所以,我使用了 GlobalScope。 而且我認為這可能會導致 memory 泄漏和不正確的行為。

@OptIn(DelicateCoroutinesApi::class)
class CustomWebSocketListener : WebSocketListener() {
    val socketEventChannel: Channel<SocketUpdate> = Channel(10)

    override fun onOpen(webSocket: WebSocket, response: Response) {
        // no-op
    }

    override fun onMessage(webSocket: WebSocket, text: String) {
        GlobalScope.launch {
            socketEventChannel.sendOrNothing(SocketUpdate(text = text))
        }
    }

    override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
        GlobalScope.launch {
            socketEventChannel.sendOrNothing(SocketUpdate(exception = SocketAbortedException()))
        }
        webSocket.close(1000, null)
        socketEventChannel.close()
    }

    override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
        GlobalScope.launch {
            socketEventChannel.sendOrNothing(SocketUpdate(exception = t))
        }
    }

    private suspend fun <E> Channel<E>.sendOrNothing(e: E) {
        try {
            this.send(e)
        } catch (e: ClosedSendChannelException) {
            e.printStackTrace()
        }
    }
}

我像這樣使用 CustomWebSocketListener:

    suspend fun startOrReloadSocket(url: String): Channel<SocketUpdate> {
        if(isConnected()) {
            if(url == webSocketUrl) {
                return webSocketListener!!.socketEventChannel
            } else {
                stopSocket()
            }
        }
        return with(CustomWebSocketListener()) {
            startOrReloadSocket(url,this)
            this@with.socketEventChannel
        }
    }

我做這個是為了使用監聽器。 如何將偵聽器包含在同一個協程 scope 中以便我可以使用 viewModelScope?(在 viewModelScope 中調用了掛起函數(startOrReloadSocket))

您可以使用suspendCoroutine塊將您的回調轉換為掛起函數。 這是一個有用的鏈接

如何在 WebSocketListener 中使用暫停 function 或 viewModelScope/lifecycleScope?

使用 trySend 生產,在 Lifecycle 上消費

eventChannel不是rendezvous通道。 因此,您只需使用trySend進行事件生成並在生命周期中使用。

生產

/**
* If you want handle result of event produce :
*
* ChannelResult result = socketEventChannel.trySend(~)
* if(result.isFailure) {
*    handle error
* }
**/

override fun onMessage(webSocket: WebSocket, text: String) {
    socketEventChannel.trySend(SocketUpdate(text = text))
}

override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
    socketEventChannel.trySend(SocketUpdate(exception = SocketAbortedException()))
    webSocket.close(1000, null)
    socketEventChannel.close()
}

override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
    socketEventChannel.trySend(SocketUpdate(exception = t))
}

消耗

viewModelScope or lifecycleScope.launch {
    listener.socketEventChannel.consumeEach {
        // TODO : handle socket event
    }
}

參考

嘗試發送

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM