日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

在Android中使用WebSocket實現消息通信的方法詳解

瀏覽:47日期:2022-09-23 13:11:43

前言

消息推送功能可以說移動APP不可缺少的功能之一,一般簡單的推送我們可以使用第三方推送的SDK,比如極光推送、信鴿推送等,但是對于消息聊天這種及時性有要求的或者三方推送不滿足業務需求的,我們就需要使用WebSocket實現消息推送功能。

基本流程

WebSocket是什么,這里就不做介紹了,我們這里使用的開源框架是https://github.com/TakahikoKawasaki/nv-websocket-client

基于開源協議我們封裝實現WebSocket的連接、注冊、心跳、消息分發、超時任務功能,基本流程如下:

在Android中使用WebSocket實現消息通信的方法詳解

連接功能

首先我們新建一個項目,在build.grade中添加配置

compile ’com.neovisionaries:nv-websocket-client:2.2’

新建websocket管理類WsManger

public class WsManager { private volatile static WsManager wsManger; private WsManager() { } public static WsManager getWsManger() { if (wsManger == null) { synchronized (WsManager.class) { if (wsManger == null) { wsManger = new WsManager(); } } } return wsManger; } }

接下來添加連接方法,我們將webSocket的狀態分為三種,新建WsStatue枚舉類對應起來

public enum WsStatus { /** * 連接成功 */ CONNECT_SUCCESS, /** * 連接失敗 */ CONNECT_FAIL, /** * 正在連接 */ CONNECTING;}

連接方法如下所示:

/** * 連接方法 這里要判斷是否登錄 此處省略 */public void connect() { //WEB_SOCKET_API 是連接的url地址, // CONNECT_TIMEOUT是連接的超時時間 這里是 5秒 try { ws = new WebSocketFactory().createSocket(WEB_SOCKET_API, CONNECT_TIMEOUT) //設置幀隊列最大值為5 .setFrameQueueSize(5) //設置不允許服務端關閉連接卻未發送關閉幀 .setMissingCloseFrameAllowed(false) //添加回調監聽 .addListener(new WsListener()) //異步連接 .connectAsynchronously(); } catch (IOException e) { e.printStackTrace(); } setStatus(WsStatus.CONNECTING);}

調用連接方法后 我們來看連接的回調 也就是WsListener

/** * websocket回調事件 */private class WsListener extends WebSocketAdapter { @Override public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception { Log.d(TAG, 'onConnected: 連接成功'); } @Override public void onConnectError(WebSocket websocket, WebSocketException exception) throws Exception { Log.d(TAG, 'onConnectError: 連接失敗'); } @Override public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception { Log.d(TAG, 'onDisconnected: 斷開連接'); } @Override public void onTextMessage(WebSocket websocket, String text) throws Exception { Log.d(TAG, 'onTextMessage: 收到消息:' + text); }}

下面我們調用連接方法

WsManager.getWsManger().connect();

運行項目我們可以看到如下打印:

在Android中使用WebSocket實現消息通信的方法詳解

此處我們要做的處理是,如果收到連接失敗或者斷開連接的回調 需要重新連接,我們重新調用一次連接方法即可,并且如果超過三次重連失敗,我們在業務中可以通過調用接口來獲取數據,避免數據丟失,此處細節省略。

協議封裝

此處協議如下所示:

{ 'action':'', 'requestChild':{ 'clientType':'', 'id':'' }}

心跳、發送請求都屬于客戶端主動發送請求,對于請求結果我們分為成功和失敗以及超時,發送超時我們是收不到服務器任何回復的,所以我們需要在發送之后將發送放在超時任務隊列中,如果請求成功將任務從超時隊列中移除,超時從超時隊列中獲取任務重新請求。

超時任務隊列中回調有成功、失敗、超時。

我們按照上述協議,新增對應實體類,采用Builder設計模式

public class Request { /** * 行為 */ private String action; /** * 請求體 */ private RequestChild req; /** * 請求次數 */ private transient int reqCount; /** * 超時的時間 */ private transient int timeOut; public Request() { } public Request(String action, int reqCount, int timeOut, RequestChild req) { this.action = action; this.req = req; this.reqCount = reqCount; this.timeOut = timeOut; } public static class Builder { //action 請求類型 private String action; //請求子類數據 按照具體業務劃分 private RequestChild req; //請求次數 便于重試 private int reqCount; //超時時間 private int timeOut; public Builder action(String action) { this.action = action; return this; } public Builder req(RequestChild req) { this.req = req; return this; } public Builder reqCount(int reqCount) { this.reqCount = reqCount; return this; } public Builder timeOut(int timeOut) { this.timeOut = timeOut; return this; } public Request build() { return new Request(action, reqCount, timeOut, req); } }}

public class RequestChild { /** * 設備類型 */ private String clientType; /** * 用于用戶注冊的id */ private String id; public RequestChild(String clientType, String id) { this.clientType = clientType; this.id = id; } public RequestChild() { } public static class Builder { private String clientType; private String id; public RequestChild.Builder setClientType(String clientType) { this.clientType = clientType; return this; } public RequestChild.Builder setId(String id) { this.id = id; return this; } public RequestChild build() { return new RequestChild(clientType, id); } } }

我們添加一個發送請求的方法如下:

/** * 發送請求 * * @param request 請求體 * @param reqCount 請求次數 * @param requestListern 請求回調 */private void senRequest(Request request, final int reqCount, final RequestListern requestListern) { if (!isNetConnect()) { requestListern.requestFailed('網絡未連接'); return; } }

請求回調如下所示

public interface RequestListern { /** * 請求成功 */ void requestSuccess(); /** * 請求失敗 * * @param message 請求失敗消息提示 */ void requestFailed(String message);}

接著我們要把請求放在超時隊列中,新建超時任務類,對應的分別是請求參數、請求回調、任務調度

public class TimeOutTask { /** * 請求主體 */ private Request request; /** * 通用返回 */ private RequestCallBack requestCallBack; /** * r任務 */ private ScheduledFuture scheduledFuture; public TimeOutTask(Request request, RequestCallBack requestCallBack, ScheduledFuture scheduledFuture) { this.request = request; this.requestCallBack = requestCallBack; this.scheduledFuture = scheduledFuture; } public ScheduledFuture getScheduledFuture() { return scheduledFuture; } public void setScheduledFuture(ScheduledFuture scheduledFuture) { this.scheduledFuture = scheduledFuture; } public Request getRequest() { return request; } public void setRequest(Request request) { this.request = request; } public RequestCallBack getRequestCallBack() { return requestCallBack; } public void setRequestCallBack(RequestCallBack requestCallBack) { this.requestCallBack = requestCallBack; } }

RequestCallBack是超時任務的回調,只是比請求回調多了個超時,因為超時的處理機制是一樣的,所以這里我們沒必要將超時回調到請求中

public interface RequestCallBack { /** * 請求成功 */ void requestSuccess(); /** * 請求失敗 * * @param request 請求體 * @param message 請求失敗的消息 */ void requestFailed(String message, Request request); /** * 請求超時 * * @param request 請求體 */ void timeOut(Request request);}/** * 添加超時任務 */private ScheduledFuture enqueueTimeout(final Request request, final long timeout) { Log.d(TAG, ' ' + 'enqueueTimeout: 添加超時任務類型為:' + request.getAction()); return executor.schedule(new Runnable() { @Override public void run() { TimeOutTask timeoutTask = callbacks.remove(request.getAction()); if (timeoutTask != null) { timeoutTask.getRequestCallBack().timeOut(timeoutTask.getRequest()); } } }, timeout, TimeUnit.MILLISECONDS);}

超時任務的方法是通過任務調度定時調用,請求成功后我們會把超時任務移除,當到了超時時間時,任務還存在就說明任務超時了。

每次的任務我們以action為鍵值存在hashMap中

private Map<String, CallbackWrapper> callbacks = new HashMap<>();

將任務放入超時任務代碼如下所示:

final ScheduledFuture timeoutTask = enqueueTimeout(request, request.getTimeOut()); final RequestCallBack requestCallBack = new RequestCallBack() { @Override public void requestSuccess() { requestListern.requestSuccess(); } @Override public void requestFailed(String message, Request request) { requestListern.requestFailed(message); } @Override public void timeOut(Request request) { timeOutHanlder(request); }};callbacks.put(request.getAction(), new CallbackWrapper(request, requestCallBack, timeoutTask));

一般而言,任務超時都是由于連接原因導致,所以我們這里可以嘗試重試一次,如果還是超時,通過 timeOutHanlder(request);方法 進行重新連接,重連代碼和連接代碼一樣,這里就省略了,做好這步操作,我們就可以發送消息了。

/** * 超時任務 */private void timeOutHanlder(Request requset) { setStatus(WsStatus.CONNECT_FAIL); //這里假裝有重連 Log.d(TAG, 'timeOutHanlder: 請求超時 準備重連');}

到這里我們的流程基本可以走通了。

心跳

首先我們要了解下心跳的作用是什么,心跳是在連接成功后,通過固定的間隔時間向服務器發送詢問,當前是否還在線,有很多人說心跳失敗我們就重連,成功就繼續心跳,但是這里要注意的是,我們一般是收不到心跳失敗回調的,心跳也是向服務器發送數據,所以我們要將所有的主動請求都放在超時任務隊列中,

所以對websocket來說 請求結果有三種:成功、失敗、超時,對于用戶 只有成功、失敗即可。

至于心跳、注冊等請求發送的數據是什么,這就得看我們與服務端定的協議是什么樣了,通常來說 分為action 和 requestBody,協議格式我們再第二步已經封裝好了,這里我們以心跳任務為例驗證上面的封裝。

/** * 心跳 */void keepAlive() { Request request = new Request.Builder() .reqCount(0) .timeOut(REQUEST_TIMEOUT) .action(ACTION_KEEPALIVE).build(); WsManager.getWsManger().senRequest(request, request.getReqCount() + 1, new RequestListern() { @Override public void requestSuccess() { Log.d(TAG, 'requestSuccess: 心跳發送成功了'); } @Override public void requestFailed(String message) { } });}

我們每間隔10s中開啟一次心跳任務

/** * 開始心跳 */public void startKeepAlive() { mHandler.postDelayed(mKeepAliveTask, HEART_BEAT_RATE);}/** * 心跳任務 */private Runnable mKeepAliveTask = new Runnable() { @Override public void run() { keepAlive(); mHandler.removeCallbacks(mKeepAliveTask); mHandler.postDelayed(mKeepAliveTask, HEART_BEAT_RATE); }};

為了便于操作演示,在主頁面上加個按鈕 ,點擊按鈕調用startKeepAlive方法,運行如下所示:

在Android中使用WebSocket實現消息通信的方法詳解

我們可以看到心跳返回的statue是300 不成功,5秒之后走到了請求超時的方法中,所以如果狀態返回成功的話,我們需要回調給調用者

/** * 處理 任務回調 * * @param action 請求類型 */void disPatchCallbackWarp(String action, boolean isSuccess) { CallbackWrapper callBackWarp = callbacks.remove(action); if (callBackWarp == null) { Logger.d(TAG+' '+ 'disPatchCallbackWarp: 任務隊列為空'); } else { callBackWarp.getScheduledFuture().cancel(true); if (isSuccess) { callBackWarp.getRequestCallBack().requestSuccess(); } else { callBackWarp.getRequestCallBack().requestFailed('', new Request()); } }}

這樣調用者才知道成功或失敗。

發送其他消息與心跳一樣,只是請求參數不同而已,修改Request參數即可。這樣我們根據協議和業務就實現一個比較規范的webSocket消息推送流程了。

到此這篇關于在Android中使用WebSocket實現消息通信的方法詳解的文章就介紹到這了,更多相關Android使用WebSocket實現消息通信內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
免费一级欧美在线观看视频 | 国产日韩欧美高清免费| 在线综合欧美| 日韩精品一区第一页| 欧美精品九九| 天堂日韩电影| 欧美日韩中文一区二区| 亚洲免费成人| 亚洲国产专区校园欧美| 中文字幕日本一区二区| 欧美日韩国产亚洲一区| 午夜在线一区二区| 欧美永久精品| 国产精品最新自拍| 国产精品多人| 国产精品精品| 日韩午夜av| 亚洲精品大片| 欧美三区四区| 亚洲一区免费| 丝袜国产日韩另类美女| 欧美~级网站不卡| 亚洲五月综合| 久久亚洲资源中文字| 99精品视频精品精品视频| 免费看黄色91| 国产在视频一区二区三区吞精| 欧美日韩国产高清| 久久超碰99| 亚洲免费婷婷| 欧美国产先锋| 亚洲在线一区| 久久久91麻豆精品国产一区| 免费毛片在线不卡| 国产精品网在线观看| 一区二区三区视频免费观看| 日韩一区网站| 日本在线高清| 国产精品视频首页| 在线精品小视频| 日韩大片免费观看| 69堂免费精品视频在线播放| 亚洲二区免费| 国产精品久久国产愉拍| 亚洲欧洲午夜| 99久久精品费精品国产| 国产伦精品一区二区三区在线播放| 91精品一区二区三区综合| 国产精品视频一区二区三区| 亚洲日韩中文字幕一区| 国内精品福利| 91欧美精品| 久久午夜精品一区二区| 久久久夜夜夜| 狠狠久久伊人| 激情久久99| 牛牛精品成人免费视频| 亚洲欧美日本国产专区一区| 日本欧美不卡| av在线最新| 国产夫妻在线| 亚洲一区国产一区| 免费中文字幕日韩欧美| 色综合视频一区二区三区日韩 | 精品一区二区男人吃奶| 亚洲精品伊人| 午夜在线精品偷拍| 国产亚洲一区二区手机在线观看 | 午夜视频一区二区在线观看| 亚洲免费成人| 视频一区二区三区入口| 中文欧美日韩| 日韩精品首页| 成人在线免费观看91| 成人在线免费观看网站| 欧美黄色网页| 伊人成人在线视频| 中文视频一区| 蜜桃免费网站一区二区三区| 噜噜噜久久亚洲精品国产品小说| 成人国产精品一区二区免费麻豆| 国产日韩高清一区二区三区在线 | 不卡福利视频| 久久久一本精品| 欧美日韩激情| 日本亚洲欧美天堂免费| 精品国产欧美日韩一区二区三区| 亚洲精品裸体| 久久不见久久见中文字幕免费| sm久久捆绑调教精品一区| 午夜国产精品视频免费体验区| 亚州欧美在线| 福利在线一区| 男女精品网站| 免费在线亚洲欧美| 亚洲午夜av| 人人爱人人干婷婷丁香亚洲| 日韩av自拍| 蜜臀av性久久久久蜜臀aⅴ四虎| 日韩精品欧美大片| 精品一区不卡| 亚洲综合图色| 国产一区二区三区不卡视频网站| 欧美三级网址| 日韩av一级片| 欧美日韩水蜜桃| 国产欧美日韩影院| 久久一级电影| 精品国产乱码久久久久久樱花| 在线日韩成人| 色吊丝一区二区| 国产亚洲一区| 久久亚洲影院| 国产99亚洲| 欧美日韩一区二区国产 | 日韩中文字幕一区二区高清99| 国内在线观看一区二区三区| 日本亚洲最大的色成网站www| 成人精品中文字幕| 国产成人精品一区二区三区视频 | 日韩三级精品| 蜜桃伊人久久| 亚洲欧美激情诱惑| 1024精品久久久久久久久| 91成人在线精品视频| 亚洲在线成人| 在线一区免费| 久久国产日韩| 神马午夜久久| 性欧美videohd高精| 国内精品美女在线观看| 久久只有精品| 欧美成人一二区| 国产精品99久久久久久董美香| 四虎精品一区二区免费| 首页欧美精品中文字幕| 亚洲一区二区三区四区五区午夜| 99香蕉国产精品偷在线观看| 久久久久国产精品一区三寸| 国产精品2023| 精品一区二区三区中文字幕在线| 国产精品一在线观看| 亚洲精品少妇| 91成人福利| av资源中文在线天堂| 91精品蜜臀一区二区三区在线| 蜜桃tv一区二区三区| 国产精品av一区二区| 国产精品7m凸凹视频分类| 天堂av在线一区| 91精品日本| 天堂√中文最新版在线| 久久天堂av| 在线国产精品一区| 欧美精选一区二区三区| 国产精品社区| 国产日韩欧美三区| 久久久久91| 精品五月天堂| 91亚洲国产成人久久精品| 国产成人精品一区二区三区在线| av资源中文在线| 99热精品在线| 国产精品成人一区二区网站软件| 成人亚洲一区二区| 黄页网站一区| 日本不卡在线视频| 在线天堂资源www在线污| 99在线精品免费视频九九视| 蜜臀久久久久久久| 国产一区二区三区不卡视频网站| 日韩视频在线一区二区三区| 国产精品一区二区av日韩在线| 欧美日韩国产免费观看视频| 国产精品宾馆| 亚洲香蕉视频| 日韩在线高清| 国产精品99久久免费| 视频在线观看91| 日本蜜桃在线观看视频| 亚洲欧美久久精品| 影院欧美亚洲| 欧洲一区二区三区精品| 国产欧美日韩一区二区三区四区| 97精品视频在线看| 国产乱子精品一区二区在线观看| 亚洲电影在线一区二区三区| 久久影院一区二区三区| 美女91精品| 亚洲一区网站| 999在线观看精品免费不卡网站| 国产一区二区三区黄网站| 免费不卡在线观看| 亚洲深爱激情| 国产视频亚洲| 日韩视频一区二区三区在线播放免费观看| 久久免费精品| 精品久久网站| 国产精品成人国产| 99国产精品视频免费观看一公开 |