Kotlin-webSocket的基本封装

作者: yooking丶毓 | 来源:发表于2020-08-19 14:31 被阅读0次

    个人博客地址:https://blog.yookingh.cn
    该文章地址:https://blog.yookingh.cn/dev/190809-webSocket.html

    前言

    • 什么是webSocket
      WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
      WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
      ——摘自百度百科

    • 应用场景

      App与服务器长连接,一般用于通讯。

    实践

    框架引入

    框架路径:
    Java-WebSocket
    OkHttp-GithubPage

    //implementation "org.java-websocket:Java-WebSocket:1.4.0"//
    //改用 square项目
    implementation 'com.squareup.okhttp3:okhttp:4.0.1'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.0.1'
    

    创建Utils类

    /**
     * @param url webSocket 服务链接
     * @param listener webSocket 消息回调 - 这里直接使用okhttp的回调/可根据需求另行封装
     */
    class WebSocketUtils(private val url: String, private val listener: WebSocketListener)
    

    初始化webSocket

    private const val TAG: String = "WebSocketLog"//日志抬头
    private const val READ_TIMEOUT: Long = 30//读取超时
    private const val WRITE_TIMEOUT: Long = 30//写入超时
    private const val CONNECT_TIMEOUT: Long = 30//连接超时
    
    private val okHttpClient: OkHttpClient
    private var webSocket: RealWebSocket
    init{
        //引入log日志
        val interceptor = HttpLoggingInterceptor(
            object : HttpLoggingInterceptor.Logger {
                override fun log(message: String) {
                    Log.d(TAG, message)
                }
            }
        )
        interceptor.level = HttpLoggingInterceptor.Level.BODY//日志等级
        okHttpClient = OkHttpClient.Builder()
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)//设置写的超时时间
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)//设置连接超时时间
            .retryOnConnectionFailure(true)//断线重连
            .addInterceptor(interceptor)//添加拦截器
            .build()
        val request: Request = Request.Builder().url(url).build()
        //创建webSocket
        webSocket = okHttpClient.newWebSocket(request, listener) as RealWebSocket
    }
    

    基本方法封装

    //发送
    fun send(message: String) {
        //这里message为与后台约定的内容 建议使用Json样式
        val isSend = webSocket.send(message)
        //发送失败可以做重新发送
        Log.d(TAG, "send-->isSend:$isSend message:$message")
    }
    
    //重连
    fun reConnect(url: String) {//替换了url
        webSocket.cancel()
        val request: Request = Request.Builder().url(url).build()
        webSocket = okHttpClient.newWebSocket(request, listener) as RealWebSocket
    }
    
    fun reConnect() {//未替换url
        reConnect(url)
    }
    
    //断开
    fun cancel() {
        webSocket.cancel()
    }
    

    心跳机制处理

    心跳的启动与关闭封装

    private const val WHAT_HEART: Int = 0//handler-what
    private const val DEFAULT_HEART_TIME: Long = 60//默认心跳时间
    /**
    * @param heartMessage 向后台服务发送的心跳消息
    * @param current 间隔时间
    */
    fun startHeart(heartMessage: String, current: Long?) {
        this.heartMessage = heartMessage
        heartTime = current!!
        handler.sendEmptyMessage(WHAT_HEART)
    }
    
    //停止心跳
    fun endHeart() {
        handler.removeMessages(WHAT_HEART)
    }
    

    心跳Handler

    //这里使用静态内部类 防止内存泄漏
    companion object {
        private class WithoutLeakHandler(wsu: WebSocketUtils) : Handler() {
            private val mWsu: WeakReference<WebSocketUtils> = WeakReference(wsu)
            override fun handleMessage(msg: Message?) {
                super.handleMessage(msg)
                val webSocketUtils = mWsu.get()!!
                //调用发送方法向后台服务发送心跳信息
                webSocketUtils.send(webSocketUtils.heartMessage)
                //webSocketUtils.heartTime之后再次发送心跳信息
                msg!!.target.sendEmptyMessageDelayed(WHAT_HEART, webSocketUtils.heartTime)
            }
        }
    }
    
    private var handler: Handler = WithoutLeakHandler(this)
    

    方法调用

    webSocketUtils = WebSocketUtils(url,object : WebSocketListener() {
        override fun onOpen(webSocket: WebSocket, response: Response) {
            super.onOpen(webSocket, response)
            Log.d(TAG, "onOpen")
        }
        
        override fun onMessage(webSocket: WebSocket, text: String) {
            super.onMessage(webSocket, text)
            Log.d(TAG, "onMessage-->text:$text")
        }
    
        override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
            super.onMessage(webSocket, bytes)
            Log.d(TAG, "onMessage-->bytes:$bytes")
        }
    
        override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
            super.onClosed(webSocket, code, reason)
            Log.d(TAG, "onClosed-->code:$code\treason$reason")
            webSocketUtils.endHeart()//停止心跳
        }
    
        override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
            super.onClosing(webSocket, code, reason)
            Log.d(TAG, "onClosing-->code:$code\treason$reason")
            webSocketUtils.endHeart()//停止心跳
        }
    
        override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
            super.onFailure(webSocket, t, response)
            Log.d(TAG, "onFailure-->throwable:$t")
            //webSocketUtils.reConnect()
            webSocketUtils.endHeart()//停止心跳
        }
    })
    
    webSocketUtils.startHeart("心跳消息", 1000)//启动心跳
    

    Demo

    Github

    补充

    建议使用Service进行webSocket连接

    相关文章

      网友评论

        本文标题:Kotlin-webSocket的基本封装

        本文链接:https://www.haomeiwen.com/subject/bfzqjktx.html