我個(gè)人用的比較好的 websocket 框架就是 WsManager 了(簡(jiǎn)單,方便,快捷)
這里簡(jiǎn)單說下 WsManager 的使用,以及斷開重連的一些操作(原本W(wǎng)sManager是自帶重連機(jī)制的(斷開重連),但是部分原因?qū)е逻@個(gè)可能會(huì)失效,下面會(huì)說到)
先來說說簡(jiǎn)單的調(diào)用;
首先添加依賴:
api 'com.rabtman.wsmanager:wsmanager:1.0.2'
實(shí)例化:
(其他資料提及到這是一個(gè)簡(jiǎn)化OkHttp Websocket使用的庫(kù))
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
WsManager wsManager = new WsManager.Builder(this)
.wsUrl("ws://localhost:8080/") //ws連接地址
.client(okHttpClient)
.build();
建立連接:
wsManager.startConnect();
設(shè)置監(jiān)聽:
wsManager.setWsStatusListener(new WsStatusListener() {
@Override
public void onOpen(Response response) { //連接成功
super.onOpen(response);
}
@Override
public void onMessage(String text) { //接收string類型數(shù)據(jù)
super.onMessage(text);
}
@Override
public void onMessage(ByteString bytes) { //接收ByteString類型數(shù)據(jù)
super.onMessage(bytes);
}
@Override
public void onReconnect() { //websocket連接中
super.onReconnect();
}
@Override
public void onClosing(int code, String reason) { //連接關(guān)閉中
super.onClosing(code, reason);
}
@Override
public void onClosed(int code, String reason) { //連接已關(guān)閉
super.onClosed(code, reason);
}
@Override
public void onFailure(Throwable t, Response response) { //連接失敗
super.onFailure(t, response);
}
});
發(fā)送websocket數(shù)據(jù):
wsManager.sendMessage(); //可發(fā)送String類型或者ByteString類型數(shù)據(jù)
斷開連接:
wsManager.stopConnect();
上面根據(jù)網(wǎng)上的一些資料,簡(jiǎn)述了下WsManager框架的使用,下面說下一些簡(jiǎn)單的封裝
這里提及一下上面說到的斷開重連,WsManager是自帶斷開重連機(jī)制沒錯(cuò),但是本人在多臺(tái)設(shè)備測(cè)試后發(fā)現(xiàn),部分華為手機(jī)存在斷開后無法重連的現(xiàn)象(還存在非常容易斷開的情況).
上代碼
<1>首先對(duì)WsManager簡(jiǎn)單封裝
/**
* MyWsManager管理類
*/
public class MyWsManager {
private final String TAG = this.getClass().getSimpleName();
private static final String DEF_RELEASE_URL = "ws://localhost:8080/"; //連接地址
private static MyWsManager wsManager;
private static WsManager myWsManager;
private Context context;
//單例
public static MyWsManager getInstance() {
if (wsManager == null) {
synchronized (MyWsManager.class) {
if (wsManager == null) {
wsManager = new MyWsManager();
}
}
}
return wsManager;
}
public void init(Context context) {
try {
myWsManager = new WsManager.Builder(context)
.client(
new OkHttpClient().newBuilder()
.pingInterval(5, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build())
.needReconnect(true)
.wsUrl(DEF_RELEASE_URL)
.build();
//.needReconnect(true) //是否需要重連
//.setHeaders(null) //設(shè)置請(qǐng)求頭
//.setReconnnectInterval(10*1000) //設(shè)置重連步長(zhǎng)(ms)
//.setReconnnectIMaxTime(30*1000) //設(shè)置重連最大時(shí)長(zhǎng)
myWsManager.setWsStatusListener(wsStatusListener);
myWsManager.startConnect();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "myWsManager-----Exception");
}
}
private WsStatusListener wsStatusListener = new WsStatusListener() {
@Override
public void onOpen(Response response) {
Log.d(TAG, "myWsManager-----onOpen");
Log.e("onOpen", "服務(wù)器連接成功");
}
@Override
public void onMessage(String text) {
Log.d(TAG, "MyWsManager-----onMessage");
Log.e("onMessage", text + "\n\n");
//在這里接收和處理收到的ws數(shù)據(jù)吧
}
@Override
public void onMessage(ByteString bytes) {
Log.d(TAG, "MyWsManager-----onMessage");
}
@Override
public void onReconnect() {
Log.d(TAG, "MyWsManager-----onReconnect");
Log.e("onReconnect", "服務(wù)器重連接中...");
}
@Override
public void onClosing(int code, String reason) {
Log.d(TAG, "MyWsManager-----onClosing");
Log.e("onClosing", "服務(wù)器連接關(guān)閉中...");
//這一步我個(gè)人認(rèn)為是比較騷的操作,上面提及了設(shè)備會(huì)出現(xiàn)斷開后無法連接的情況,那這種無法連接的情
//況我發(fā)現(xiàn)有可能會(huì)卡在這個(gè)關(guān)閉過程中,因?yàn)槿绻谴_實(shí)斷開后會(huì)確實(shí)的啟動(dòng)重連機(jī)制,至于還有別的坑
//我后面會(huì)補(bǔ)充;這里主要的目的就死讓他跳出這個(gè)關(guān)閉中的狀態(tài),確實(shí)的關(guān)閉了ws先
if (myWsManager != null) {
myWsManager.stopConnect();
myWsManager.startConnect();
}
}
@Override
public void onClosed(int code, String reason) {
Log.d(TAG, "MyWsManager-----onClosed");
Log.e("onClosed", "服務(wù)器連接已關(guān)閉...");
}
@Override
public void onFailure(Throwable t, Response response) {
Log.d(TAG, "MyWsManager-----onFailure");
Log.e("onFailure", "服務(wù)器連接失敗...");
}
};
//發(fā)送ws數(shù)據(jù)
public void sendDataD(String content) {
if (myWsManager != null && myWsManager.isWsConnected()) {
boolean isSend = myWsManager.sendMessage(content);
if (isSend) {
Log.e("onOpen sendMessage", "發(fā)送成功");
} else {
Log.e("onOpen sendMessage", "發(fā)送失敗");
}
} else {
//Toast.makeText(mContext, "請(qǐng)先連接服務(wù)器", Toast.LENGTH_SHORT).show();
}
}
//斷開ws
public void disconnect() {
if (myWsManager != null)
myWsManager.stopConnect();
}
}
然后只需要在需要調(diào)用的地方:
MyWsManager.getInstance().init(mContext); //連接socket
MyWsManager.getInstance().disconnect(); //斷開socket
好,簡(jiǎn)單的封裝和調(diào)用也有了,這里就講講我個(gè)人是怎么處理斷開后無法重連的方法,方法很簡(jiǎn)單:
首先講講思路,當(dāng)時(shí)測(cè)試了不少方法最后發(fā)現(xiàn)ws的根本無法自動(dòng)重連,感覺像進(jìn)程卡在那了一樣
那么我想到的最簡(jiǎn)單的辦法就是手動(dòng)去斷開然后重連,那么我們什么情況下去斷開呢?
其實(shí)我這種做法就是ws在連接服務(wù)器后,需要模擬一個(gè)心跳機(jī)制,就是定時(shí)的發(fā)送數(shù)據(jù)到服務(wù)器,然后服務(wù)器相應(yīng)的反饋表示已收到,然后再加個(gè)定時(shí)器,設(shè)置一個(gè)間隔期,假如沒有收到服務(wù)器反饋啦,就默認(rèn)他已經(jīng)掛了,那么我們就重新去初始化一次.
<2>
(1)弄個(gè)倒計(jì)時(shí)的工具類 然后再計(jì)時(shí)完畢(就是在一段間隔期后沒有收到反饋,則調(diào)用初始化ws)
class TimeCount extends CountDownTimer {
public TimeCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@SuppressLint("SetTextI18n")
@Override
public void onTick(long millisUntilFinished) { // 計(jì)時(shí)過程
}
@Override
public void onFinish() {// 計(jì)時(shí)完畢
Log.e("TimeCount >>>", "計(jì)時(shí)完畢");
MyWsManager.getInstance().disconnect(); //斷開socket
MyWsManager.getInstance().init(mContext);
}
}
(2)在MyWsManager管理類監(jiān)聽onMessage中加上反饋處理
比如我這里用到EventBus作為傳輸數(shù)據(jù)的方式,在使用的地方處理他
EventBus.getDefault().postSticky("connect");
(3)接收反饋的消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void getEventBusSocket(String connect) {
//收到反饋,定時(shí)器刷新,這樣只要一斷開連接超過一定時(shí)間 則調(diào)用此方法 初始化ws,達(dá)到斷開重連效果
if(connect.equals("connect")){
time.cancel();
time.start();
}
}
(4)啟動(dòng)計(jì)時(shí)器即可
private TimeCount time;
//20s websocket無響應(yīng)則重啟
time = new TimeCount(20000, 1000);
代碼很齊全,就不貼demo之類的了,有更好的方式希望大家可以跟我分享