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() } }
问题分析
- 事件监听未重新绑定:重连时通过
setSocket()创建了新的Socket实例,但DisplayActivity中之前绑定的事件监听器仍指向旧Socket对象,新Socket未重新注册监听事件,导致无法接收服务器数据。 - 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
相关产品推荐
相关产品推荐

