場景
Android中将谊,“搜索”事件無非下面兩種場景:
1蹂析、從網(wǎng)絡(luò)中搜索資源
2、從本地(緩存借杰、內(nèi)存)中搜索資源
下面是個搜索的gif过吻,要做到最優(yōu)體驗,首先應(yīng)該盡量避免無用的計算工作以及占用無意義的資源蔗衡。
最優(yōu)解
1纤虽、從網(wǎng)絡(luò)中搜索資源
因為網(wǎng)絡(luò)資源需要流量的開銷,并且網(wǎng)絡(luò)請求過程不容易控制绞惦,所以該解決方案主要從流量逼纸、性能方便考慮。
設(shè)置一個延遲時間济蝉,過濾掉變化過快的字符:
比如設(shè)置延時時間為200ms杰刽,當(dāng)用戶輸入'a'后,200ms內(nèi)沒輸入新的字符王滤,則200ms后贺嫂,根據(jù)‘a(chǎn)’來搜索首字母為'a'的數(shù)據(jù)源;
如果用戶輸入'a'后雁乡,緊接著很快輸入了'b'第喳,'c'(每個字符間隔時間小于200ms),則在'c'輸入200ms后踱稍,根據(jù)'abc'來搜索首字母為'abc'的數(shù)據(jù)源曲饱。
總結(jié):該方案非常適合搜索網(wǎng)絡(luò)資源時使用吩跋。這種方案有效減少不必要的流量開銷,提升了用戶體驗渔工。
安利:如果你使用了RxJava,一個操作符就可以幫你搞定:Debounce桥温。Debounce操作符會過濾掉發(fā)射速率過快的數(shù)據(jù)項引矩。這里有一篇簡友翻譯的使用RxJava提升用戶體驗的簡書。
2侵浸、從本地(緩存旺韭、內(nèi)存)中搜索資源
因為從本地中搜索資源相比較網(wǎng)絡(luò)中速度較快,整個搜索過程完全可控掏觉,所以該解決方案主要從搜索速度上考慮区端。
單個子線程處理搜索,配合標(biāo)志位澳腹,及時停止無意義的搜索過程:
比如當(dāng)用戶輸入'a'织盼,會立刻進(jìn)行查找,如果直到查找到結(jié)果也沒有新的字符變化時酱塔,則顯示結(jié)果沥邻;如果在查找過程中,用戶緊接著輸入'b'羊娃,則立即停止'a'的搜索過程唐全,重新以'ab'字符開始搜索首字母為'ab'的數(shù)據(jù)源。
總結(jié):該方案非常適合搜索本地資源時使用蕊玷。這種方案查找搜索結(jié)果是最高效的邮利。
談?wù)剬崿F(xiàn)
上述兩種解決方案都可以使用HandlerThread + 標(biāo)志位的方式實現(xiàn)。
HanlderThread本質(zhì)就是Thread + Looper垃帅,想深入了解HandlerThread的延届,可以查看Hongyang大神的這篇博客
另外有一種更科學(xué)的方式:SingleThreadExecutor線程池;相比HandlerThread挺智,線程池配合Future可以用更簡潔的代碼實現(xiàn)我們的需求祷愉。
下面以這種場景為例:
// 創(chuàng)建 SingleThreadExecutor
mExecutorService = Executors.newSingleThreadExecutor();
// 每當(dāng)數(shù)據(jù)變化時調(diào)用
void onDataChanged() {
if (mFuture != null) {
// 數(shù)據(jù)變化時,取消上一個任務(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
}
});
}
});
}
上面代碼就是整個實現(xiàn)過程了赦颇,注釋應(yīng)該解釋的很清楚啦二鳄,就不多廢話了。
至于第一種方案的實現(xiàn)媒怯,如果不用RxJava的話订讼,使用HandlerThread也是可以實現(xiàn)的,不需要標(biāo)志位(網(wǎng)絡(luò)請求一般是不可控的扇苞,標(biāo)志位沒什么意義)欺殿,而是配合Hanlderd的removeCallbacks
方法寄纵,或者removeMessages
方法移除Callback/Messages。具體實現(xiàn)感興趣的脖苏,可以自己去試試吧程拭。