概述
WebSocket是一种在单个TCP连接上进行全双工通信的协议,特别适合实时通信场景。在Android开发中,我们通常使用OkHttp库来实现WebSocket功能。
使用步骤
-
添加依赖
在项目的 build.gradle 文件中添加OkHttp依赖:dependencies { implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0' } -
添加网络权限
在 AndroidManifest.xml 中添加网络权限:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -
创建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) } } -
在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() } }
高级用法
-
发送二进制数据
// 发送字节数组 val bytes = "Hello World".toByteArray() val byteString = ByteString.of(*bytes) webSocketManager.sendBytes(byteString) -
心跳检测
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 } } -
自动重连
class WebSocketManager { private var reconnectAttempts = 0 private val maxReconnectAttempts = 5 private fun attemptReconnect() { if (reconnectAttempts < maxReconnectAttempts) { reconnectAttempts++ Handler(Looper.getMainLooper()).postDelayed({ connect() }, 2000 * reconnectAttempts) // 指数退避 } } }
注意事项
- 线程安全: WebSocket回调在后台线程执行,需要使用Handler切换到主线程更新UI
- 生命周期管理: 在Activity/Fragment销毁时记得断开WebSocket连接
- 网络权限: 确保应用有网络访问权限
- 错误处理: 实现完善的错误处理和重连机制
- 内存泄漏: 避免在回调中持有Activity的强引用
总结
通过以上步骤,可以在Android应用中成功集成WebSocket功能。WebSocketManager类封装了连接、发送、接收和断开等核心功能,使用简单且功能完整。
469

被折叠的 条评论
为什么被折叠?



