WebSocket安卓客戶端實現詳解(三)–服務端主動通知
本篇依舊是接着上一篇繼續擴展,還沒看過之前博客的小夥伴,這裏附上前幾篇地址
終於是最後一篇啦,有點激動\ ( ≧▽≦ ) /啦啦啦,
服務端主動通知
熱身完畢,我們先回顧下第一篇中講到的服務端主動通知的流程
根據notify中事件類型找到對應的處理類,處理對應邏輯.
然後用eventbus通知對應的ui界面更新.
如果需要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使用我已經盡我所能最詳細的講解了一遍,但是也避免不了有所疏漏和錯誤還望各位小夥伴指出.
然後雖然寫了三篇但是還有幾個點說的不夠詳細,這裏我一一列舉感興趣的小夥伴可以自己看看.
獲取連接地址與選擇連接地址的策略
重連的策略
心跳的策略
進程保活
最後感謝各位小夥伴捧場能把三篇都看完的絕對是真愛啊…