WQthrottle 是一款訊息防抖框架,在一定的時間延時中做到只觸發一次結果的回撥。
使用
使用的話,還是看 github 的 README 吧。
開發目的
開發這款框架的初衷是為了解決以下的幾個痛點:
- 多餘的操作請求
- 多頁面訊息傳遞
痛點一(多餘的操作請求)
這個痛點在我們的業務中經常出現,下面列出兩個比較常見的業務操作:
點贊
在我們設計點讚的時候,每點選一次 贊
操作都會請求伺服器,以告知伺服器當前是 點贊
操作還是 取消贊
操作,如果使用者這時頻繁去點贊,就會導致過多的網路請求,產生了不必要的浪費。對於設計層面來說,點贊功能無非就是兩種狀態,贊或是沒贊
,我們完全可以等待使用者停止操作後再去請求伺服器。
搜尋
實時搜尋展示搜尋內容也是我們平時業務中比較常見的功能,我們給 EditText 註冊 TextWatcher 監聽,在 onTextChanged 中實時拿到使用者輸入的內容然後請求網路,看似一段沒有任何問題的操作,就敗在不同使用者的輸入習慣,有的人打字非常慢,打入一些片語,onTextChanged 收到訊息立馬請求伺服器顯示結果,而有的人打字非常快,而且每打一個片語就回車到 EditText 上,這就會導致頻繁的網路請求,更糟糕的情況就是頻繁的頁面渲染,100次請求就會導致100次的頁面渲染。
痛點二(多頁面訊息傳遞)
在剛接觸 Android 開發時,頁面的訊息傳遞一般都是 Intent ,回傳通過 setResult 將結果帶回上一個頁面,非常蛋疼的操作,直到後來出現 EventBus
,在業內非常流行,一款非常解耦的框架,可以做到在任何地方傳送訊息和接收訊息,但對於我來說,缺點還是蠻多的:
- Subcribe 太隨意,導致後面專案亂,不好維護
- Eventbus 的內部實現原理是反射,效能問題需要斟酌
- 每次 post 一個訊息過去都要想,我這個 bean 會不會影響到其他的訊息接收,算了,還是建立一個 bean 類吧
原理剖析
實現原理非常簡單, 就一個核心東西------《Handler》
初始化
初始化操作使用的單例,他會預設構造一個 handler 處理類:
handler = HandlerFactory.create(HandlerType.MAIN_THREAD, callBacks);
複製程式碼
HandlerType 是一個列舉類,該列舉主要為了告知接收器是在主執行緒還是子執行緒,具體可看 HandlerFactory 類。
註冊
註冊非常簡單,就是註冊一個 CallBack 介面,等 post 訊息時,會一一回撥註冊的 callback
private List<CallBack> callBacks = new ArrayList<>();
public void register(CallBack callBack) {
callBacks.add(callBack);
}
複製程式碼
傳送訊息
傳送訊息整個框架的核心部分:
WQThrottle.getInstance().delay(int tag, long timeMillis, Object params);
複製程式碼
我們來看下 delay 做的什麼東西:
public void delay(int tag, long timeMillis, Object params) {
handler.removeMessages(tag);
Message msg = handler.obtainMessage();
msg.obj = params;
msg.what = tag;
handler.sendMessageDelayed(msg, timeMillis);
}
複製程式碼
還是非常簡單,就是在 delay 時間內,移除之前觸發的訊息,然後重新傳送訊息,直到使用者不觸發了,等 delay 時間到了,訊息就會傳送出去了。
訊息接收
訊息的接收需要先看看回撥部分的程式碼:
new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
sendMessages(msg, callBacks);
}
};
private static void sendMessages(Message msg, List<WQThrottle.CallBack> callBacks) {
for (int i = 0, len = callBacks.size(); i < len; i++) {
callBacks.get(i).throttleResult(msg.what, msg.obj);
}
}
複製程式碼
傳送的訊息被 Handler 接收到了,會遍歷所有 CallBack 註冊介面,將資訊 post 出去。
@Override
public void throttleResult(int tag, Object obj) {
switch(tag){//do something}
}
複製程式碼
CallBack 根據傳送的 tag 進行比較,確定是什麼操作,然後取出引數 obj。
結束
整個設計非常簡單,僅僅只通過 Handler 就實現了基於訊息的框架。
話不多,就這樣吧