android 使用Okhttp3实现 websocket 连接并实现通信

呃那个,最近公司项目又用到了websocket,呃,其实,这个东西我也不是很懂,目前也是从网上学习和抄写了,不过,也是自己整理了一下,不能算抄袭,自我觉得,顶多算是借鉴,哈哈,自我安慰的一种体现哈,下面,我直接上正题,不啰嗦

1、首先,我们要想将okhttp3引进项目中取,你可以从网上找jar包引入,呃,这里不提供,我这里提供从android studio 里面的buile.gradle里面,Eclipse我不怎么用了意思很相近,如果你用Eclipse,那自己琢磨吧

  implementation 'com.squareup.okhttp3:okhttp:3.9.0'

这个时候已经将okhttp引入项目了,很方便吧,呃,这个,如果你的studio 版本是3.1以上,恩,对,应该是,这个版本以上,这里用implementation ,如果是以下,可能就需要用

   compile'com.squareup.okhttp3:okhttp:3.9.0'

这两个都是引入的哈,因为工具版本不一样,对了权限别忘记了

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

2、这个时候,就加我们的wsmananger,用于连接与交互

public class WsManager implements IWsManager {
    private final static int RECONNECT_INTERVAL = 10 * 1000;    //重连自增步长
    private final static long RECONNECT_MAX_TIME = 120 * 1000;   //最大重连间隔
    private Context mContext;
    private String wsUrl;
    private WebSocket mWebSocket;
    private OkHttpClient mOkHttpClient;
    private Request mRequest;
    private int mCurrentStatus = WsStatus.DISCONNECTED;     //websocket连接状态
    private boolean isNeedReconnect;          //是否需要断线自动重连
    private boolean isManualClose = false;         //是否为手动关闭websocket连接
    private Lock mLock;
    private Handler wsMainHandler = new Handler(Looper.getMainLooper());
    private int reconnectCount = 0;   //重连次数
    private Runnable reconnectRunnable = new Runnable() {
        @Override
        public void run() {
            Log.e("websocket", "服务器重连接中...");
            buildConnect();
        }
    };
    private static VideoPresenter videoPresenter = new VideoPresenter();
    private WebSocketListener mWebSocketListener = new WebSocketListener() {

        @Override
        public void onOpen(WebSocket webSocket, final Response response) {
            mWebSocket = webSocket;
            setCurrentStatus(WsStatus.CONNECTED);
            connected();
            if (Looper.myLooper() != Looper.getMainLooper()) {
                JSONObject jo = new JSONObject();
                jo.put("act", 1);
                jo.put("projectname", App.getConfig().getProjectname());
                jo.put("mac", App.getConfig().getMac());
                jo.put("lightid", App.getConfig().getLightid());
                jo.put("version", App.getConfig().getVcode());
//                    jo.put("act", 1);
//                    jo.put("data", App.getConfig());
                sendMessage(jo.toJSONString());
            } else {
                Log.e("websocket", "服务器连接成功");
            }
        }

        @Override
        public void onMessage(WebSocket webSocket, final ByteString bytes) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                wsMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("websocket", "WsManager-----onMessage");
                    }
                });
            } else {
                Log.e("websocket", "WsManager-----onMessage");
            }
        }

        @Override
        public void onMessage(WebSocket webSocket, final String text) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                wsMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("websocket", "WsManager-----onMessage");
                    }
                });
            } else {
                Log.e("websocket", "WsManager-----onMessage");
            }
        }

        @Override
        public void onClosing(WebSocket webSocket, final int code, final String reason) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                wsMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("websocket", "服务器连接关闭中");
                    }
                });
            } else {
                Log.e("websocket", "服务器连接关闭中");
            }
        }

        @Override
        public void onClosed(WebSocket webSocket, final int code, final String reason) {

            if (Looper.myLooper() != Looper.getMainLooper()) {
                wsMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("websocket", "服务器连接已关闭");
                    }
                });
            } else {
                Log.e("websocket", "服务器连接已关闭");
            }
        }

        @Override
        public void onFailure(WebSocket webSocket, final Throwable t, final Response response) {
            try {
                tryReconnect();
                Log.e("liusehngjei", "[走的链接失败这里!!!!!!!!!!!!!!!!]");
                if (Looper.myLooper() != Looper.getMainLooper()) {
                    wsMainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Log.e("websocket", "服务器连接失败");
                        }
                    });
                } else {
                    Log.e("websocket", "服务器连接失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    public WsManager(Builder builder) {
        mContext = builder.mContext;
        wsUrl = builder.wsUrl;
        isNeedReconnect = builder.needReconnect;
        mOkHttpClient = builder.mOkHttpClient;
        this.mLock = new ReentrantLock();
    }

    private void initWebSocket() {
        if (mOkHttpClient == null) {
            mOkHttpClient = new OkHttpClient.Builder()
                    .retryOnConnectionFailure(true)
                    .build();
        }
        if (mRequest == null) {
            mRequest = new Request.Builder()
                    .url(wsUrl)
                    .build();
        }
        mOkHttpClient.dispatcher().cancelAll();
        try {
            mLock.lockInterruptibly();
            try {
                mOkHttpClient.newWebSocket(mRequest, mWebSocketListener);
            } finally {
                mLock.unlock();
            }
        } catch (InterruptedException e) {
        }
    }

    @Override
    public WebSocket getWebSocket() {
        return mWebSocket;
    }


    @Override
    public synchronized boolean isWsConnected() {
        return mCurrentStatus == WsStatus.CONNECTED;
    }

    @Override
    public synchronized int getCurrentStatus() {
        return mCurrentStatus;
    }

    @Override
    public synchronized void setCurrentStatus(int currentStatus) {
        this.mCurrentStatus = currentStatus;
    }

    @Override
    public void startConnect() {
        isManualClose = false;
        buildConnect();
    }

    @Override
    public void stopConnect() {
        isManualClose = true;
        disconnect();
    }

    private void tryReconnect() {
        if (!isNeedReconnect | isManualClose) {
            return;
        }
        Log.e("liusehngjei", "reconnectCount2222222[" + reconnectCount + "]");
        if (!isNetworkConnected(mContext)) {
            setCurrentStatus(WsStatus.DISCONNECTED);
            Log.e("liusehngjei", "[请您检查网络,未连接]");
//            return;
        }
        setCurrentStatus(WsStatus.RECONNECT);
        Log.e("liusehngjei", "reconnectCount11111111[" + reconnectCount + "]");
        long delay = reconnectCount * RECONNECT_INTERVAL;
//        wsMainHandler.postDelayed(reconnectRunnable, delay > RECONNECT_MAX_TIME ? RECONNECT_MAX_TIME : delay);
        wsMainHandler.postDelayed(reconnectRunnable, 10000);
        Log.e("liusehngjei", "reconnectCount[" + reconnectCount + "]");
        reconnectCount++;

    }

    private void cancelReconnect() {
        wsMainHandler.removeCallbacks(reconnectRunnable);
        reconnectCount = 0;
    }

    private void connected() {
        cancelReconnect();
    }

    private void disconnect() {
        if (mCurrentStatus == WsStatus.DISCONNECTED) {
            return;
        }
        cancelReconnect();
        if (mOkHttpClient != null) {
            mOkHttpClient.dispatcher().cancelAll();
        }
        if (mWebSocket != null) {
            boolean isClosed = mWebSocket.close(WsStatus.CODE.NORMAL_CLOSE, WsStatus.TIP.NORMAL_CLOSE);
            //非正常关闭连接
            if (!isClosed) {
                Log.e("websocket", "服务器连接失败");
            }
        }
        setCurrentStatus(WsStatus.DISCONNECTED);
    }

    private synchronized void buildConnect() {
        if (!isNetworkConnected(mContext)) {
            setCurrentStatus(WsStatus.DISCONNECTED);
//            return;
        }
        switch (getCurrentStatus()) {
            case WsStatus.CONNECTED:
            case WsStatus.CONNECTING:
                break;
            default:
                setCurrentStatus(WsStatus.CONNECTING);
                initWebSocket();
        }
    }

    //发送消息
    @Override
    public boolean sendMessage(String msg) {
        return send(msg);
    }

    @Override
    public boolean sendMessage(ByteString byteString) {
        return send(byteString);
    }

    private boolean send(Object msg) {
        boolean isSend = false;
        if (mWebSocket != null && mCurrentStatus == WsStatus.CONNECTED) {
            if (msg instanceof String) {
                isSend = mWebSocket.send((String) msg);
            } else if (msg instanceof ByteString) {
                isSend = mWebSocket.send((ByteString) msg);
            }
            //发送消息失败,尝试重连
            if (!isSend) {
                tryReconnect();
            }
        }
        return isSend;
    }

    //检查网络是否连接
    private boolean isNetworkConnected(Context context) {
        if (context != null) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            @SuppressLint("MissingPermission") NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {
                return mNetworkInfo.isAvailable();
            }
        }
        return false;
    }

    public static final class Builder {

        private Context mContext;
        private String wsUrl;
        private boolean needReconnect = true;
        private OkHttpClient mOkHttpClient;

        public Builder(Context val) {
            mContext = val;
        }

        public Builder wsUrl(String val) {
            wsUrl = val;
            return this;
        }

        public Builder client(OkHttpClient val) {
            mOkHttpClient = val;
            return this;
        }

        public Builder needReconnect(boolean val) {
            needReconnect = val;
            return this;
        }

        public WsManager build() {
            return new WsManager(this);
        }

    }
}

3、里面还有一个接口需要

interface IWsManager {

  WebSocket getWebSocket();

  void startConnect();

  void stopConnect();

  boolean isWsConnected();

  int getCurrentStatus();

  void setCurrentStatus(int currentStatus);

  boolean sendMessage(String msg);

  boolean sendMessage(ByteString byteString);
}

4、还有一个工具类,记录状态

public class WsStatus {

  public final static int CONNECTED = 1;
  public final static int CONNECTING = 0;
  public final static int RECONNECT = 2;
  public final static int DISCONNECTED = -1;

  class CODE {

    public final static int NORMAL_CLOSE = 1000;
    public final static int ABNORMAL_CLOSE = 1001;
  }

  class TIP {

    public final static String NORMAL_CLOSE = "normal close";
    public final static String ABNORMAL_CLOSE = "abnormal close";
  }
}

5、下面就是调用链接了,在调用界面首先要实例化WsMnanger

WsManager wsManager = new WsManager.Builder(getBaseContext()).client(
                new OkHttpClient().newBuilder()
                        .pingInterval(15, TimeUnit.SECONDS)
                        .retryOnConnectionFailure(true)
                        .build())
                .needReconnect(true)
                .wsUrl("ws://192.168.3.145:80/MayaCloud_Lightpush//ws")
                .build();
6、连接可以直接使用
  wsManager.startConnect();

7、停止链接使用下面方法

 
 
  if (wsManager != null) {
      wsManager.stopConnect();
      wsManager = null;
  }

8、在onDestory()里面要记得停止链接

  @Override
    protected void onDestroy() {
        if (wsManager != null) {
            wsManager.stopConnect();
            wsManager = null;
        }
    }

9、哦了,就这么简单,里面做了断线重连机制,我设定的是,当断线后,十秒后重连,一般这个时间都能接受,时间太短,会导致卡死,所以,十秒应该还是能接受的,

10、结束语:如果大神看到,有不足的地方,还望大神批评指正,小弟一定更改,力求做到更好,今天仅在此记录此功能,需要demo的请链接下方地址,由于小弟没有积分了,特希望各位能不计较这点小分,此demo是一个聊天的功能,默认链接的地址是测试服务器,跑通后可以直接使用,具体不懂的,可以在里面自己查看

资源Demo



猜你喜欢

转载自blog.csdn.net/qaz520929/article/details/80496281