前言
之前我们介绍过服务端使用WebSocket如何设计数据框架,现在我们看看客户端如何与它通讯。
如果光说要用WebSocket做一个例子,相信很多小伙伴都能搞通,网上这么多资料。随便拿一个过来,调通就行了。不过,做出来与把它做好是两码事。我们的目标是,不但要把数据调通,还要把它梳理完善,加入设计元素把它整理成一个程序框架,这样,你不仅积累了经验,也拥有了自己的知识资产,将来扩展功能时,或者再开一个新项目,可以花较少的精力,以最快的速度完成任务。
这就是框架的作用。
本文假定读者已经具有一定Android基础知识,重点介绍怎么样搭建数据通讯框架。
基本数据结构
之前我们讲过,基础的数据结构我们这么定:
action$$txNo&$$data
action是这个发送的指令名称,txNo是交易号,data就是系列化后的json文本。
比如登录请求,客户端发送的数据是这样的:
LOGIN$$1725876358993$${"username":"003","password":"123456"}
服务端验证通过后会返回这样的信息
LOGIN$$1725876358993$${"code":200,"msg":"Success","data":{"userId":4, "username":"003", "realName":"王老五"}}
如果没通过,服务端的回应会是这样:
LOGIN$$1725876358993$${"code":500, "msg":"用户名或密码错误"}
数据结构是不是很简单。(因为CSDN显示问题,分隔符美元符号这里用全角的符号)
WebSocket通用类
WebSocket的协议比较简单,很容易理解,除了连接关闭,主要就是收和发。这里我们讨论文本的收发。
早些时候,Android程序大都采用RESTful与服务端交互,现在如果服务端提供的是WebSocket了,现在怎么搞呢?
老规矩,我们先找一个轮子,即底层通讯框架,注意不是造,是找。我们不想花精力在这些基础的东西上,费时费力还一时半会儿做不出稳定的东西。
Android开发 的小伙伴都知道,之前使用RESTful时我们一般用的ok.http这个框架与服务端通讯
实际上,它也可以用于WebSocket。虽然也有很多其它的框架,但是大家既然对ok.http比较习惯了,我们还是用它。
我们先利用ok.http编写一个WSClient的类。注意,这个类必须设计成一个通用的工具类,不能包含任何业务逻辑。
package com.bob.app.common;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.MutableLiveData;
import com.bob.app.C;
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class WSClient {
private static MutableLiveData<String> mld;
private static WebSocket socket;
public static void init() {
if (socket != null) {
return;
}
OkHttpClient.Builder cb = new OkHttpClient.Builder();
cb.readTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);// 5 seconds
cb.connectTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);
cb.writeTimeout(C.SOCKET_TIMEOUT, TimeUnit.SECONDS);
cb.connectionPool(new ConnectionPool(32, 5, TimeUnit.MINUTES));
OkHttpClient client = cb.build();
Request request = new Request.Builder().url(C.serverUrl).build();
socket = client.newWebSocket(request, new WSListener());
}
public synchronized static void send(String action, Object data, MutableLiveData<String> mld) {
if (socket == null) {
init();
}
WSClient.mld = mld;
long txNo = System.currentTimeMillis();
String messag