Android websocket使用(WsManager)

我個(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之類的了,有更好的方式希望大家可以跟我分享

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容