5

Search is central in my app and I need it to work well. Right now I have a SearchView. I need to display the results inline, so I'm using this code.

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            srl.setVisibility(View.GONE);
            return false;
        }

        @Override
        public boolean onQueryTextChange(String query) {
            currentQuery = query;
            if (query.length()>= 3) {
                searchFor(currentQuery);
            } else {
                srl.setVisibility(View.GONE);
            }
            return false;
        }
    });

The problem may be obvious. Because I use firebase, my searchFor() function is rather heavy and I don't need it to be executed for every single letter. This not only destroys the user experience, it sometimes literally crashes my app if you write down longer words.

What I want is to search when the user stops typing. I guess I need to have a handler that delays it by a second and then cancel that handler everytime a letter key is pressed and set a new one. This theoretically makes sense. I just haven't been able to pull this off myself for a searchView.

Help would be appreciated!

azizbekian
  • 60,783
  • 13
  • 169
  • 249
Vic V
  • 1,080
  • 2
  • 12
  • 31
  • You've got the right idea, and there are plenty of examples here already: http://stackoverflow.com/q/34955109, http://stackoverflow.com/q/30047665, etc. What problems are you having, specifically? – Mike M. Mar 26 '17 at 20:27
  • Possible duplicate of [Android Throttle onQueryTextChange SearchView](http://stackoverflow.com/questions/34955109/android-throttle-onquerytextchange-searchview) – X3Btel Mar 26 '17 at 20:45

3 Answers3

5

The easiest way to achieve that is RxJava's debounce operator.

enter image description here

With combination of Jake Wharton's RxBinding you'll end up with something like this:

RxSearchView.queryTextChanges(searchView)
        .debounce(1, TimeUnit.SECONDS) // stream will go down after 1 second inactivity of user
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<CharSequence>() {
            @Override
            public void accept(@NonNull CharSequence charSequence) throws Exception {
                // perform necessary operation with `charSequence`
            }
        });
azizbekian
  • 60,783
  • 13
  • 169
  • 249
  • I feel like this is the right answer, but I'm missing an import. Action1 is part of RxSearchView's support lib, but Studio won't let met import / extend it. – Vic V Mar 26 '17 at 20:54
  • Just type "new ", IDEA will prompt you with appropriate callback. This is RxJava 1, you have imported RxJava 2. – azizbekian Mar 26 '17 at 20:55
  • I'm not fully versed in RxJava yet, but I found that replacing `Action1` with `Consumer` and `call()` with `accept()`, it works. It seems to have the desired effect. Thanks! – Vic V Mar 26 '17 at 21:29
3

For those who do not want to use RxJava :

final Handler handler = new Handler();
SearchView searchView = (SearchView) findViewById(R.id.search_view);

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

        public boolean onQueryTextChange(final String query) {
            handler.removeCallbacksAndMessages(null);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // do stuff
                }
            }, 400);
            return false;
        }
});
Arcyno
  • 4,153
  • 3
  • 34
  • 52
1

This should help you, your class need to implement "SearchView.OnQueryTextListener" and "cntr" must be declarated in your class

This is already twinked for a regular user typing, if you want to wait more, just raise the "waitingTime".

The request should be inside the "onFinish"

    private int waitingTime = 200;
    private CountDownTimer cntr;

    @Override
    public boolean onQueryTextChange(String newText) {
    if(cntr != null){
        cntr.cancel();
    }
    cntr = new CountDownTimer(waitingTime, 500) {

        public void onTick(long millisUntilFinished) {
            Log.d("TIME","seconds remaining: " + millisUntilFinished / 1000);
        }

        public void onFinish() {
            Log.d("FINISHED","DONE");
        }
    };
    cntr.start();
    return false;
}

Reference: Delay call to onQueryTextChange() in SearchView.OnQueryTextListener with SearchView

C. Hellmann
  • 556
  • 6
  • 13