1 2 3 4

代理转发

Android WebSocketListenermProxyListener 代理转发写法理解

这篇笔记用于理解:在 Android OkHttp WebSocket 封装中,为什么常见写法是内部维护一个 wsListener,同时再保存一个外部传入的 mProxyListener

核心结论:

OkHttp -> 内部 wsListener -> mProxyListener -> 外部业务逻辑

wsListener 负责封装层统一处理,mProxyListener 负责把事件继续交给业务层。

1. 场景与角色

OkHttp 创建 WebSocket 时,需要传入一个 WebSocketListener

client.newWebSocket(request, listener)

这个 listener 会在连接打开、收到消息、连接失败、关闭等时机被 OkHttp 回调。

如果你自己封装了一个 WebSocketClient,通常会有两类监听器:

  • wsListener:封装层内部监听器,真正传给 OkHttp。
  • mProxyListener:外部业务层传入的监听器,保存在封装类内部。

也就是说,OkHttp 并不会直接回调业务层的 listener,而是先回调封装层的 wsListener

2. 回调链路

完整链路如下:

OkHttp WebSocket 事件
        |
        v
内部 wsListener
        |
        | 先做封装层统一逻辑
        | 例如日志、状态管理、重连、心跳、线程切换
        v
mProxyListener
        |
        | 再交给外部业务层
        v
业务逻辑

所以 mProxyListener 的本质是一个“外部回调出口”。

3. Kotlin 抽象示例

import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString

class MyWebSocketClient {

    companion object {
        private const val TAG = "MyWebSocketClient"
    }

    // 外部业务层注入的 listener。
    private var mProxyListener: WebSocketListener? = null

    // 内部 listener:真正传给 OkHttp。
    private val wsListener: WebSocketListener = object : WebSocketListener() {

        override fun onOpen(webSocket: WebSocket, response: Response) {
            // 1. 封装层统一逻辑
            Log.d(TAG, "connect open")

            // 2. 转发给外部业务层
            mProxyListener?.onOpen(webSocket, response)
        }

        override fun onMessage(webSocket: WebSocket, text: String) {
            Log.d(TAG, "receive text message")
            mProxyListener?.onMessage(webSocket, text)
        }

        override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
            Log.d(TAG, "receive binary message")
            mProxyListener?.onMessage(webSocket, bytes)
        }

        override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
            Log.d(TAG, "connect closing: code=$code, reason=$reason")
            mProxyListener?.onClosing(webSocket, code, reason)
        }

        override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
            Log.d(TAG, "connect closed: code=$code, reason=$reason")
            mProxyListener?.onClosed(webSocket, code, reason)
        }

        override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
            Log.e(TAG, "connect failure", t)
            mProxyListener?.onFailure(webSocket, t, response)
        }
    }

    fun setListener(listener: WebSocketListener?) {
        mProxyListener = listener
    }

    fun connect(client: OkHttpClient, request: Request) {
        // OkHttp 实际回调的是内部 wsListener。
        client.newWebSocket(request, wsListener)
    }
}

4. 外部业务层怎么使用

业务层只需要传入自己的监听器,实现真正关心的逻辑:

val client = MyWebSocketClient()

client.setListener(object : WebSocketListener() {

    override fun onOpen(webSocket: WebSocket, response: Response) {
        // 业务逻辑:例如通知 UI 已连接、发送鉴权消息等。
    }

    override fun onMessage(webSocket: WebSocket, text: String) {
        // 业务逻辑:例如解析消息、分发到业务模块等。
    }

    override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
        // 业务逻辑:例如提示错误、上报异常等。
    }

    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
        // 业务逻辑:例如更新连接状态、释放资源等。
    }
})

业务层不需要知道封装层内部如何管理日志、心跳、重连,只需要关心自己的业务事件。

5. 为什么不直接把业务 listener 传给 OkHttp

如果直接把外部业务 listener 传给 OkHttp,封装层就失去了统一拦截点。

使用内部 wsListener 再转发给 mProxyListener,可以在转发前后插入通用能力:

  • 统一日志记录。
  • 统一连接状态管理。
  • 自动重连。
  • 心跳检测。
  • 鉴权流程。
  • 线程切换,例如从 OkHttp 回调线程切到主线程再通知 UI。
  • try-catch 防御,避免业务回调抛异常影响封装层。

因此,这种写法本质上是代理模式或装饰器模式:

外部业务 listener 没有直接交给 OkHttp,
而是被封装层保存起来,
由内部 wsListener 在合适的时候调用它。

6. super.onXxx(...) 通常有没有必要

大多数情况下没有必要。

OkHttp 的 WebSocketListener 默认实现通常是空实现,也就是 no-op:

override fun onOpen(webSocket: WebSocket, response: Response) {
    super.onOpen(webSocket, response) // 通常可以省略
}

所以在 Kotlin 或 Java 中,通常可以直接省略 super.onOpen(...)super.onMessage(...)super.onFailure(...) 等调用。

7. 与 C++ 的对应关系

可以把 Kotlin/Java 的 listener 理解成 C++ 中保存的一组 callback。

Kotlin / Java C++
WebSocketListener 一组回调函数,或一个 listener 接口类
object : WebSocketListener() { ... } lambda、仿函数、匿名实现
mProxyListener 保存用户传入的 callback 成员变量
内部 wsListener 先处理再转发 包装一层 callback,先做内部逻辑,再调用用户 callback

8. C++ std::function 对照示例

#include <functional>
#include <iostream>
#include <string>

struct Callbacks {
  std::function<void()> onOpen;
  std::function<void(const std::string&)> onMessage;
};

class Client {
  Callbacks internal_; // 内部统一入口,相当于 wsListener。
  Callbacks proxy_;    // 用户注入,相当于 mProxyListener。

public:
  Client() {
    internal_.onOpen = [this] {
      std::cout << "connect open\n";      // 内部统一逻辑。

      if (proxy_.onOpen) {
        proxy_.onOpen();                  // 转发给用户。
      }
    };

    internal_.onMessage = [this](const std::string& message) {
      std::cout << "receive message: " << message << '\n';

      if (proxy_.onMessage) {
        proxy_.onMessage(message);
      }
    };
  }

  void setListener(const Callbacks& callbacks) {
    proxy_ = callbacks;
  }
};

这里的关系和 Kotlin 版本一致:

底层事件 -> internal_ -> proxy_ -> 用户逻辑

9. 一句话记忆

mProxyListener 就是业务层 listener 的保存位置。

内部 wsListener 负责拦截 OkHttp 的回调,先做封装层通用逻辑,再调用 mProxyListener,把事件转发给外部业务层。

posted @ 2026-04-28 11:00  y丶innocence  阅读(8)  评论(0)    收藏  举报