Android WebSocket 使用步骤说明和使用示例

概述

WebSocket是一种在单个TCP连接上进行全双工通信的协议,特别适合实时通信场景。在Android开发中,我们通常使用OkHttp库来实现WebSocket功能。

使用步骤

  1. 添加依赖
    在项目的 build.gradle 文件中添加OkHttp依赖:

    dependencies {
        implementation 'com.squareup.okhttp3:okhttp:4.12.0'
        implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
    }
    
  2. 添加网络权限
    在 AndroidManifest.xml 中添加网络权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
  3. 创建WebSocket管理器
    基于您的WebSocketManager,创建一个WebSocket连接管理器:

    import android.os.Handler
    import android.os.Looper
    import okhttp3.*
    import okhttp3.logging.HttpLoggingInterceptor
    import okio.ByteString
    import java.util.concurrent.TimeUnit
    
    class WebSocketManager(
        private val url: String,
        private val enableLog: Boolean = true,
        private val onMessage: (String) -> Unit,
        private val onConnectionChange: (Boolean) -> Unit,
        private val onError: (Throwable) -> Unit
    ) {
        private var webSocket: WebSocket? = null
        private val client: OkHttpClient
        private val mainHandler = Handler(Looper.getMainLooper())
        @Volatile
    	private var isClosedManually: Boolean = false
    
        init {
            client = OkHttpClient.Builder()
            	.pingInterval(120, TimeUnit.SECONDS)
           		.retryOnConnectionFailure(true)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
            if (enableLog) {
                val logging = HttpLoggingInterceptor()
                logging.level = HttpLoggingInterceptor.Level.BODY
                client.addInterceptor(logging)
        	}
            client.build()
        }
    
        fun connect(headers: Map<String, String> = emptyMap()) {
        	isClosedManually = false
            val requestBuilder = Request.Builder()
                .url(url)
            
            // 添加自定义头部
            headers.forEach { (key, value) ->
                requestBuilder.addHeader(key, value)
            }
            
            val request = requestBuilder.build()
            
            webSocket = client.newWebSocket(request, object : WebSocketListener() {
                override fun onOpen(webSocket: WebSocket, response: Response) {
                    mainHandler.post {
                        onConnectionChange(true)
                    }
                }
    
                override fun onMessage(webSocket: WebSocket, text: String) {
                    mainHandler.post {
                        onMessage(text)
                    }
                }
    
                override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                    mainHandler.post {
                        onMessage(bytes.utf8())
                    }
                }
    
                override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                    mainHandler.post {
                        onConnectionChange(false)
                    }
                }
    
                override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                    mainHandler.post {
                        onError(t)
                    }
                    if (!isClosedManually) {
                		reconnectWithBackoff()
            		}
                }
            })
        }
    
        fun sendText(text: String): Boolean {
            return webSocket?.send(text) ?: false
        }
    
        fun sendBytes(bytes: ByteString): Boolean {
            return webSocket?.send(bytes) ?: false
        }
    
        fun disconnect() {
        	isClosedManually = true
            webSocket?.close(1000, "正常关闭")
            webSocket = null
        }
    
        fun isConnected(): Boolean {
            return webSocket != null
        }
        // 简单重连:指数退避,最大 30 秒
        @Volatile private var retryAttempt: Int = 0
        private fun reconnectWithBackoff() {
            val delay = ((1 shl retryAttempt).coerceAtMost(30)).toLong() // 1,2,4,...,30 秒
            retryAttempt = (retryAttempt + 1).coerceAtMost(5)
            mainHandler.postDelayed({
                if (!isClosedManually) connect()
            }, delay * 1000)
        }
    }
    
  4. 在Activity或Fragment中使用

    import android.os.Bundle
    import android.util.Log
    import android.widget.Button
    import android.widget.EditText
    import android.widget.TextView
    import androidx.appcompat.app.AppCompatActivity
    import okio.ByteString
    
    class MainActivity : AppCompatActivity() {
        private lateinit var webSocketManager: WebSocketManager
        private lateinit var statusText: TextView
        private lateinit var messageText: TextView
        private lateinit var inputText: EditText
        private lateinit var connectButton: Button
        private lateinit var disconnectButton: Button
        private lateinit var sendButton: Button
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            initViews()
            initWebSocket()
            setupListeners()
        }
    
        private fun initViews() {
            statusText = findViewById(R.id.statusText)
            messageText = findViewById(R.id.messageText)
            inputText = findViewById(R.id.inputText)
            connectButton = findViewById(R.id.connectButton)
            disconnectButton = findViewById(R.id.disconnectButton)
            sendButton = findViewById(R.id.sendButton)
        }
    
        private fun initWebSocket() {
            val wsUrl = "ws://your-websocket-server.com:8080/websocket"
            
            webSocketManager = WebSocketManager(
                url = wsUrl,
                onMessage = { message ->
                    runOnUiThread {
                        messageText.append("收到消息: $message\n")
                    }
                },
                onConnectionChange = { isConnected ->
                    runOnUiThread {
                        statusText.text = if (isConnected) "已连接" else "未连接"
                        connectButton.isEnabled = !isConnected
                        disconnectButton.isEnabled = isConnected
                        sendButton.isEnabled = isConnected
                    }
                },
                onError = { error ->
                    runOnUiThread {
                        Log.e("WebSocket", "连接错误", error)
                        statusText.text = "连接错误: ${error.message}"
                    }
                }
            )
        }
    
        private fun setupListeners() {
            connectButton.setOnClickListener {
                // 可以添加自定义头部
                val headers = mapOf(
                    "Authorization" to "Bearer your-token",
                    "User-Agent" to "Android-App"
                )
                webSocketManager.connect(headers)
            }
    
            disconnectButton.setOnClickListener {
                webSocketManager.disconnect()
            }
    
            sendButton.setOnClickListener {
                val message = inputText.text.toString()
                if (message.isNotEmpty()) {
                    val success = webSocketManager.sendText(message)
                    if (success) {
                        messageText.append("发送消息: $message\n")
                        inputText.text.clear()
                    } else {
                        messageText.append("发送失败\n")
                    }
                }
            }
        }
    
        override fun onDestroy() {
            super.onDestroy()
            webSocketManager.disconnect()
        }
    }
    

高级用法

  1. 发送二进制数据

    // 发送字节数组
    val bytes = "Hello World".toByteArray()
    val byteString = ByteString.of(*bytes)
    webSocketManager.sendBytes(byteString)
    
  2. 心跳检测

    class WebSocketManager {
        private var heartbeatTimer: Timer? = null
        
        private fun startHeartbeat() {
            heartbeatTimer = Timer()
            heartbeatTimer?.scheduleAtFixedRate(object : TimerTask() {
                override fun run() {
                    if (isConnected()) {
                        sendText("ping")
                    }
                }
            }, 0, 30000) // 每30秒发送一次心跳
        }
        
        private fun stopHeartbeat() {
            heartbeatTimer?.cancel()
            heartbeatTimer = null
        }
    }
    
  3. 自动重连

    class WebSocketManager {
        private var reconnectAttempts = 0
        private val maxReconnectAttempts = 5
        
        private fun attemptReconnect() {
            if (reconnectAttempts < maxReconnectAttempts) {
                reconnectAttempts++
                Handler(Looper.getMainLooper()).postDelayed({
                    connect()
                }, 2000 * reconnectAttempts) // 指数退避
            }
        }
    }
    

注意事项

  1. 线程安全: WebSocket回调在后台线程执行,需要使用Handler切换到主线程更新UI
  2. 生命周期管理: 在Activity/Fragment销毁时记得断开WebSocket连接
  3. 网络权限: 确保应用有网络访问权限
  4. 错误处理: 实现完善的错误处理和重连机制
  5. 内存泄漏: 避免在回调中持有Activity的强引用

总结

通过以上步骤,可以在Android应用中成功集成WebSocket功能。WebSocketManager类封装了连接、发送、接收和断开等核心功能,使用简单且功能完整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝加点糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值