You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Socket.io重连问题:离线后无法恢复连接接收数据

Android Socket.io 重连后无法接收服务器数据问题

问题现象

应用离线时Socket连接断开,重新上线后执行重连操作,Logcat显示连接已建立,但无法接收服务器端推送的数据。

现有实现代码

SocketHandler 管理类

import io.socket.client.IO
import io.socket.client.Socket
import java.net.URISyntaxException
import android.util.Log

object SocketHandler {
    private const val SERVER_URL = "MY_URL"
    private lateinit var msocket: Socket

    @Synchronized
    fun setSocket() {
        try {
            val options = IO.Options()
            options.forceNew = true
            msocket = IO.socket(SERVER_URL, options)
        } catch (e: URISyntaxException) {
            Log.e("SocketHandler", "Error creating socket: $e")
        }
    }

    @Synchronized
    fun establishConnection() {
        msocket.connect()
        Log.e("SocketHandler", "Connection Established")
    }

    @Synchronized
    fun closeConnection() {
        msocket.disconnect()
        Log.e("SocketHandler", "Connection DISCONNECT")
    }

    @Synchronized
    fun getSocket(): Socket {
        return msocket
    }
}

MainActivity 初始化连接

class MainActivity : FragmentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化并建立Socket连接
        SocketHandler.setSocket()
        SocketHandler.establishConnection()
        // ...其他代码
   }
}

DisplayActivity 使用连接及重连逻辑

class Display : FragmentActivity() {

// 初始化Socket实例用于监听和发送数据
var msocket = SocketHandler.getSocket()

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_display)
   }

// 网络状态监听回调中执行重连
fun onNetworkConnected() {
        SocketHandler.setSocket()
        SocketHandler.establishConnection()
        msocket = SocketHandler.getSocket()
}
}

问题分析

  1. 事件监听未重新绑定:重连时通过setSocket()创建了新的Socket实例,但DisplayActivity中之前绑定的事件监听器仍指向旧Socket对象,新Socket未重新注册监听事件,导致无法接收服务器数据。
  2. forceNew参数的影响:options.forceNew = true会强制生成新Socket实例,旧实例的监听器不会自动迁移到新实例上。

解决方案

方案1:统一管理事件监听,重连时自动绑定

修改SocketHandler,新增事件监听注册方法,确保每次创建新Socket后自动重新绑定所有需要的事件:

object SocketHandler {
    private const val SERVER_URL = "MY_URL"
    private lateinit var msocket: Socket
    // 存储全局事件监听器
    private val eventListeners = mutableMapOf<String, Socket.Listener>()

    @Synchronized
    fun setSocket() {
        try {
            val options = IO.Options()
            options.forceNew = true
            msocket = IO.socket(SERVER_URL, options)
            // 重连后自动注册所有事件
            registerAllListeners()
        } catch (e: URISyntaxException) {
            Log.e("SocketHandler", "Error creating socket: $e")
        }
    }

    // 注册单个事件监听
    @Synchronized
    fun registerEventListener(eventName: String, listener: Socket.Listener) {
        eventListeners[eventName] = listener
        // 若Socket已初始化,立即绑定
        if (::msocket.isInitialized) {
            msocket.on(eventName, listener)
        }
    }

    // 批量注册所有存储的事件
    private fun registerAllListeners() {
        eventListeners.forEach { (event, listener) ->
            msocket.on(event, listener)
        }
    }

    // 移除指定事件监听
    @Synchronized
    fun removeEventListener(eventName: String) {
        eventListeners.remove(eventName)
        if (::msocket.isInitialized) {
            msocket.off(eventName)
        }
    }

    // 原有方法保持不变
    @Synchronized
    fun establishConnection() {
        msocket.connect()
        Log.e("SocketHandler", "Connection Established")
    }

    @Synchronized
    fun closeConnection() {
        msocket.disconnect()
        Log.e("SocketHandler", "Connection DISCONNECT")
    }

    @Synchronized
    fun getSocket(): Socket {
        return msocket
    }
}

在DisplayActivity中通过SocketHandler注册监听,不再直接操作Socket实例:

class Display : FragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_display)

        // 通过SocketHandler注册事件监听
        SocketHandler.registerEventListener("your_event_name") { args ->
            // 处理服务器推送的数据
            Log.d("DisplayActivity", "Received data: ${args[0]}")
        }
    }

    // 网络重连时只需调用以下方法,无需重新赋值msocket
    fun onNetworkConnected() {
        SocketHandler.setSocket()
        SocketHandler.establishConnection()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 页面销毁时移除监听,避免内存泄漏
        SocketHandler.removeEventListener("your_event_name")
    }
}

方案2:使用Socket.io内置自动重连机制

Socket.io默认支持自动重连,无需手动创建新Socket实例。修改SocketHandler配置,启用内置重连:

object SocketHandler {
    private const val SERVER_URL = "MY_URL"
    private lateinit var msocket: Socket

    @Synchronized
    fun setSocket() {
        try {
            val options = IO.Options()
            // 启用自动重连(默认开启,可显式设置)
            options.reconnection = true
            // 设置最大重连尝试次数
            options.reconnectionAttempts = 5
            // 设置重连间隔(单位:毫秒)
            options.reconnectionDelay = 1000
            msocket = IO.socket(SERVER_URL, options)
        } catch (e: URISyntaxException) {
            Log.e("SocketHandler", "Error creating socket: $e")
        }
    }

    // 原有方法保持不变
    @Synchronized
    fun establishConnection() {
        msocket.connect()
        Log.e("SocketHandler", "Connection Established")
    }

    @Synchronized
    fun closeConnection() {
        msocket.disconnect()
        Log.e("SocketHandler", "Connection DISCONNECT")
    }

    @Synchronized
    fun getSocket(): Socket {
        return msocket
    }
}

这种方式下,网络恢复后Socket会自动尝试重连,无需手动调用setSocket(),只需确保事件监听绑定在唯一的Socket实例上即可。

内容的提问来源于stack exchange,提问作者Navi_Here

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:45:38