Chức năng search với RxJava.

Search là một fuction phổ biến mà hầu hết các ứng dụng đều cần. Chúng ta cùng nhìn lại cách thức mà chứng ta thường implement một fuction search trong ứng dụng

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                if (!newText.isEmpty()) {
                    searchData(newText); // call api search data
                }
                return true;
            }
        });

ở ví dụ trên chúng ta có thể nhận thấy mỗi khi chúng ta thay đổi text trên searchview thì đều thực hiện request đến server để thực hiện lấy dữ liệu. Việc tạo quá nhiều reuquest đến server quả thực là một điều không tốt . Vậy có cách nào chúng ta có thể tránh việc này xảy ra. Có rất nhiều cách để giải quyết được vấn đề này đơn giản chúng ta có thể check thời gian gọi api để thực hiện delay cho mỗi lần gọi hoặc cũng có thể sử dụng rxjava, rxbinding để giải quyết vấn đề này . Trong bài viết này mình sẽ giới thiệu đến các bạn cách sử dụng rxjava và rxbinding để làm việc với searchview.

Sử dụng rxjava

Sử dụng rxjava thì chắc chắn việc đầu tiền chúng ta nghĩ đến là tạo một Observable. Ở đây mình sẽ tạo một Observable emit ra text trên searchview

public class RxSearch {

    public static Observable<String> fromSearchView(@NonNull final SearchView searchView) {
        final BehaviorSubject<String> subject = BehaviorSubject.create("");

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

            @Override
            public boolean onQueryTextSubmit(String query) {
                subject.onCompleted();
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                if (!newText.isEmpty()) {
                    subject.onNext(newText);
                }
                return true;
            }
        });

        return subject;
    }
}

Thực hiện bắt sự thay đổi của searchview

RxSearch.fromSearchView(searchView)
                .debounce(300, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(query -> {
                     searchData(newText); // call api search data
                });

Ở đây chúng ta sẽ sử dụng operator debounce để delay việc call api

Sử dụng rxbinding

Có một cách đơn giản hơn rất nhiều đó là sử dụng thêm một thư viện là RxBinding

RxTextView.textChanges(searchTextView)
	.filter(new Func1<String, Boolean> (){
		@Override
		public Boolean call(String s) {
			return s.length() > 2;
		}
	})
	.debounce(100, TimeUnit.MILLISECONDS)
	.switchMap(new Func1<String, Observable<List<Result>>>() {
		makeApiCall(s);
	})
	.subscribeOn(Schedulers.io())
	.observeOn(AndroidSchedulers.mainThread())
	.subscribe(/* attach observer */);