一款簡單的訊息防抖框架

codelang發表於2019-02-28

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 就實現了基於訊息的框架。

話不多,就這樣吧

相關文章