談?wù)劇八阉鳌保?種場景下的最優(yōu)解

場景

Android中,“搜索”事件無非下面兩種場景:
1、從網(wǎng)絡(luò)中搜索資源
2、從本地(緩存、內(nèi)存)中搜索資源

下面是個(gè)搜索的gif,要做到最優(yōu)體驗(yàn),首先應(yīng)該盡量避免無用的計(jì)算工作以及占用無意義的資源。


search.gif

最優(yōu)解

1、從網(wǎng)絡(luò)中搜索資源

因?yàn)榫W(wǎng)絡(luò)資源需要流量的開銷,并且網(wǎng)絡(luò)請求過程不容易控制,所以該解決方案主要從流量、性能方便考慮。

設(shè)置一個(gè)延遲時(shí)間,過濾掉變化過快的字符:

比如設(shè)置延時(shí)時(shí)間為200ms,當(dāng)用戶輸入'a'后,200ms內(nèi)沒輸入新的字符,則200ms后,根據(jù)‘a(chǎn)’來搜索首字母為'a'的數(shù)據(jù)源;

如果用戶輸入'a'后,緊接著很快輸入了'b','c'(每個(gè)字符間隔時(shí)間小于200ms),則在'c'輸入200ms后,根據(jù)'abc'來搜索首字母為'abc'的數(shù)據(jù)源。

總結(jié):該方案非常適合搜索網(wǎng)絡(luò)資源時(shí)使用。這種方案有效減少不必要的流量開銷,提升了用戶體驗(yàn)。

安利:如果你使用了RxJava,一個(gè)操作符就可以幫你搞定:Debounce。Debounce操作符會(huì)過濾掉發(fā)射速率過快的數(shù)據(jù)項(xiàng)。這里有一篇簡友翻譯的使用RxJava提升用戶體驗(yàn)的簡書。

2、從本地(緩存、內(nèi)存)中搜索資源

因?yàn)閺谋镜刂兴阉髻Y源相比較網(wǎng)絡(luò)中速度較快,整個(gè)搜索過程完全可控,所以該解決方案主要從搜索速度上考慮。

單個(gè)子線程處理搜索,配合標(biāo)志位,及時(shí)停止無意義的搜索過程:

比如當(dāng)用戶輸入'a',會(huì)立刻進(jìn)行查找,如果直到查找到結(jié)果也沒有新的字符變化時(shí),則顯示結(jié)果;如果在查找過程中,用戶緊接著輸入'b',則立即停止'a'的搜索過程,重新以'ab'字符開始搜索首字母為'ab'的數(shù)據(jù)源。

總結(jié):該方案非常適合搜索本地資源時(shí)使用。這種方案查找搜索結(jié)果是最高效的。

談?wù)剬?shí)現(xiàn)

上述兩種解決方案都可以使用HandlerThread + 標(biāo)志位的方式實(shí)現(xiàn)。
HanlderThread本質(zhì)就是Thread + Looper,想深入了解HandlerThread的,可以查看Hongyang大神的這篇博客

另外有一種更科學(xué)的方式:SingleThreadExecutor線程池;相比HandlerThread,線程池配合Future可以用更簡潔的代碼實(shí)現(xiàn)我們的需求。

下面以這種場景為例:

 // 創(chuàng)建 SingleThreadExecutor
 mExecutorService = Executors.newSingleThreadExecutor();
 // 每當(dāng)數(shù)據(jù)變化時(shí)調(diào)用 
 void onDataChanged() {
      if (mFuture != null) {
          // 數(shù)據(jù)變化時(shí),取消上一個(gè)任務(wù)
          mFuture.cancel(true);
      }
      // 執(zhí)行異步任務(wù)
      mFuture = mExecutorService.submit(new Runnable() {
        @Override
         public void run() {
            final ArrayList<Result> resultDatas = filterDatas(datas);
            post(new Runnable() {
                @Override
                public void run() {
                    // 根據(jù)resultDatas 更新UI
                }
            });
          }
      });
  }

上面代碼就是整個(gè)實(shí)現(xiàn)過程了,注釋應(yīng)該解釋的很清楚啦,就不多廢話了。

至于第一種方案的實(shí)現(xiàn),如果不用RxJava的話,使用HandlerThread也是可以實(shí)現(xiàn)的,不需要標(biāo)志位(網(wǎng)絡(luò)請求一般是不可控的,標(biāo)志位沒什么意義),而是配合Hanlderd的removeCallbacks方法,或者removeMessages方法移除Callback/Messages。具體實(shí)現(xiàn)感興趣的,可以自己去試試吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容