WebSocket安卓客戶端實現詳解(三)--服務端主動通知

WebSocket安卓客戶端實現詳解(三)–服務端主動通知

本篇依舊是接着上一篇繼續擴展,還沒看過之前博客的小夥伴,這裏附上前幾篇地址

WebSocket安卓客戶端實現詳解(一)–連接建立與重連

WebSocket安卓客戶端實現詳解(二)–客戶端發送請求

終於是最後一篇啦,有點激動\ ( ≧▽≦ ) /啦啦啦,

服務端主動通知


熱身完畢,我們先回顧下第一篇中講到的服務端主動通知的流程

  1. 根據notify中事件類型找到對應的處理類,處理對應邏輯.

  2. 然後用eventbus通知對應的ui界面更新.

  3. 如果需要ack,發送ack請求.

在回顧下第二篇中服務端主動通知協議的格式

{
    "resp_event": 20,
    "action": "",
    "seq_id": 11111111,
    "resp": {

      }
    }
}

我們根據resp_event爲20判斷這次響應是服務端主動通知,然後通過action找到對應處理類,然後把resp中數據解析成對應的bean傳入對應處理類執行對應業務邏輯.

show code

public class WsManager {

  ....跟之前相同代碼省略.....

  class WsListener extends WebSocketAdapter {
      @Override
      public void onTextMessage(WebSocket websocket, String text) throws Exception {
          super.onTextMessage(websocket, text);
          Logger.t(TAG).d("receiverMsg:%s", text);

          Response response = Codec.decoder(text);//解析出第一層bean
          if (response.getRespEvent() == 10) {//響應
              CallbackWrapper wrapper = callbacks.remove(
                      Long.parseLong(response.getSeqId()));//找到對應callback
              if (wrapper == null) {
                  Logger.t(TAG).d("(action:%s) not found callback", response.getAction());
                  return;
              }

              try {
                  wrapper.getTimeoutTask().cancel(true);//取消超時任務
                  ChildResponse childResponse = Codec.decoderChildResp(
                          response.getResp());//解析第二層bean
                  if (childResponse.isOK()) {

                      Object o = new Gson().fromJson(childResponse.getData(),
                              wrapper.getAction().getRespClazz());

                      wrapper.getTempCallback().onSuccess(o);
                  } else {
                      wrapper.getTempCallback()
                              .onError(ErrorCode.BUSINESS_EXCEPTION.getMsg(), wrapper.getRequest(),
                                      wrapper.getAction());
                  }
              } catch (JsonSyntaxException e) {
                  e.printStackTrace();
                  wrapper.getTempCallback()
                          .onError(ErrorCode.PARSE_EXCEPTION.getMsg(), wrapper.getRequest(),
                                  wrapper.getAction());
              }

          } else if (response.getRespEvent() == 20) {//通知
              NotifyListenerManager.getInstance().fire(response);
          }
      }

  }

  ....跟之前相同代碼省略.....

}

我們先解析出第一層bean然後根據resp_event爲20執行NotifyListenerManager通知管理類對外暴露的fire()方法.

public class NotifyListenerManager {
    private final String TAG = this.getClass().getSimpleName();
    private volatile static NotifyListenerManager manager;
    private Map<String, INotifyListener> map = new HashMap<>();

    private NotifyListenerManager() {
        regist();
    }

    public static NotifyListenerManager getInstance() {
        if (manager == null) {
            synchronized (NotifyListenerManager.class) {
                if (manager == null) {
                    manager = new NotifyListenerManager();
                }
            }
        }
        return manager;
    }

    private void regist() {
        map.put("notifyAnnounceMsg", new AnnounceMsgListener());
    }

    public void fire(Response response) {
        String action = response.getAction();
        String resp = response.getResp();
        INotifyListener listener = map.get(action);
        if (listener == null) {
            Logger.t(TAG).d("no found notify listener");
            return;
        }

        NotifyClass notifyClass = listener.getClass().getAnnotation(NotifyClass.class);
        Class<?> clazz = notifyClass.value();
        Object result = null;
        try {
            result = new Gson().fromJson(resp, clazz);
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        }
        Logger.t(TAG).d(result);
        listener.fire(result);
    }


}

NotifyListenerManager是一個單例的類,在第一次創建的時候在構造方法中執行了regist方法,這是一個變種的觀察者模式對於添加觀察者這個過程我們直接在regist方法中寫好了,如果增加了新的業務邏輯我們只需要在regist方法中put新添加的action與對應處理類.對外暴露的fire方法根據傳入的responsse中action找到對應的處理類,拿到處理類對應的註解標記的class,將服務端返回的resp解析成對應的bean丟到對應處理類執行對應邏輯.

//抽象接口
public interface INotifyListener<T> {
    void fire(T t);
}

//標記註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotifyClass {

    Class<?> value();

}

//具體邏輯對應的處理子類
@NotifyClass(AnnounceMsgNotify.class)
public class AnnounceMsgListener implements INotifyListener<AnnounceMsgNotify> {

    @Override
    public void fire(AnnounceMsgNotify announceMsgNotify) {
        //這裏處理具體的邏輯
    }
}

//對應數據bean
public class AnnounceMsgNotify {
    @SerializedName("msg_version")
    private String msgVersion;

    public String getMsgVersion() {
        return msgVersion;
    }

    public void setMsgVersion(String msgVersion) {
        this.msgVersion = msgVersion;
    }

}

如果新增業務邏輯我們只需要實現新的業務邏輯類,然後在NotifyListenerManager的regist方法中put新增的action與listener映射關係,對外只需要調用NotifyListenerManager.getInstance().fire(response)即可,實現瞭解耦.

到此websocket介紹完啦….鼓掌鼓掌鼓掌.

總結


對於websocket使用我已經盡我所能最詳細的講解了一遍,但是也避免不了有所疏漏和錯誤還望各位小夥伴指出.

然後雖然寫了三篇但是還有幾個點說的不夠詳細,這裏我一一列舉感興趣的小夥伴可以自己看看.

  1. 獲取連接地址與選擇連接地址的策略

  2. 重連的策略

  3. 心跳的策略

  4. 進程保活

最後感謝各位小夥伴捧場能把三篇都看完的絕對是真愛啊…

源碼下載WebSocket安卓客戶端實現詳解(三)–服務端主動通知

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章