生活随笔
收集整理的這篇文章主要介紹了
搜索词联想功能实现方案
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
需求背景:
實現搜索框的搜索聯想功能,當輸入框輸入字符時候,立刻進行網絡請求,將相關推薦展示在下方的列表中,要求每次展示的一定是當前最新輸入的內容的推薦詞。
實現思路:
展示搜索詞聯想需要滿足如下三點:
1.搜索框輸入內容發生變化需要立刻進行網絡請求搜索關聯詞匯
2.搜索詞輸入內容變化較快,需要保證每次展示出來的聯想詞都是輸入框中最新的輸入內容所對應的聯想詞
3.每當有新的請求時候需要及時取消掉現在正在進行的網絡請求,以免網絡資源浪費。
綜合以上三點,發現網上上一些現有方案都是基于RXjava實現,在一個外文培訓網站發現一個較為完善的方案,通過debounce、filter、distinctUntilChanged、switchMap幾個方法來滿足以上三點功能,這樣原本復雜的邏輯處理就通過簡單的幾個鏈式調用完成了,修改補充后的代碼如下:
editText.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}@Overridepublic void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}@Overridepublic void afterTextChanged(Editable editable) {if (!TextUtils.isEmpty(editText.getText().toString())) {if(publishSubject!=null) {publishSubject.onNext(editText.getText().toString());}} }});private void initPublishSubject() {compositeDisposable = new CompositeDisposable();publishSubject = PublishSubject.create();Disposable disposable = publishSubject.debounce(300, TimeUnit.MILLISECONDS).filter(new Predicate<String>() {@Overridepublic boolean test(String s) throws Exception {if(TextUtils.isEmpty(s)){return false;} else {return true;}}}).distinctUntilChanged().switchMap(new Function<String, ObservableSource<ArrayList<String>>>() {@Overridepublic ObservableSource<ArrayList<String>> apply(String s) throws Exception {return getSearchObservable(s);}}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {@Overridepublic void accept(Object o) throws Exception {ArrayList<String> list = (ArrayList<String>)o;if(list!=null && list.size()!=0) {//將返回的聯想詞展示到列表中}}}, new Consumer<Throwable>() {@Overridepublic void accept(Throwable throwable) throws Exception {MyLog.d(TAG,"fail:" + throwable.getMessage());//因publishSubject如果拋出一次異常就會就會結束,所以在進入異常處理后,再次調用onnext是不會將數據發射出去的,需要重新進行初始化initPublishSubject()}});compositeDisposable.add(disposable);}private Observable<ArrayList<String>> getSearchObservable(final String query) {return Observable.create(new ObservableOnSubscribe<ArrayList<String>>() {@Overridepublic void subscribe(ObservableEmitter<ArrayList<String>> observableEmitter) throws Exception {ArrayList<String> list = new ArrayList<>();try {//通過網絡獲取聯想詞,將其賦值給list列表} catch (Exception e) {if (!observableEmitter.isDisposed()) {observableEmitter.onError(e);}}observableEmitter.onNext(list);}}).subscribeOn(Schedulers.io());}
得到搜索聯想詞之后就是將其填充到recycleview中,這一步較為簡單這里不再詳述,主要對以上代碼中使用的主要RXjava操作符簡單解析如下:
1.Debounce
僅在過了一段指定的時間后還沒有發射數據時才發射一個數據主要用于過濾掉發射速率太快的數據,比如以上代碼中,如果首次輸入了a,然后在指定的300毫秒時間間隔內,有輸入了b,此時就會過濾掉數據a,重新以ab為開始,重新等待300毫秒,如果這300毫秒內沒有新的輸入,就發射數據ab,如果有新的輸入比如c,就過濾掉數據ab,以數據abc為新的數據繼續等待300毫秒,如果300毫秒時間到了,沒有新的輸入,就發射數據abc,這樣的好處是過濾掉了一些中間不必要的數據。
2.Filter:
使用一個指定的函數測試數據,只有通過測試的數據才能夠發射,比如以上代碼中,只有非空的數據才能夠發射,空數據則過濾掉
3.DistinctUntilChanged:
DistinctUntilChanged與distinct操作符類似,功能都是避免重復,只允許通過未發射過的數據,假設最后一個請求的搜索詞是abc,然后用戶又馬上刪除了C,然后又再次輸入一個c這樣搜索詞依然是abc,這樣最后的這個abc的請求就會過濾掉。
4.SwitchMap:
switchMap運算符用于避免多余的網絡呼叫結果,該結果對于顯示給用戶而言并不需要更多,只需要最新一次的結果即可。假設最后輸入的是ab,如果正在進行ab的聯想詞請求時候用戶又繼續輸入了c,此時用戶只對abc的聯想詞感興趣,而不再需要ab的聯想詞,switchMap正好可以解決這個問題,它僅返回最新的搜索結果而忽略掉之前在進行的請求。
總結
以上是生活随笔為你收集整理的搜索词联想功能实现方案的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。