20

Using a SearchView in my application.

Is there anyway in which I can make the call to onQueryTextChange() method delayed. Like, when user type a sequence of characters, he must wait before this method gets called.

This wait should not depend on number of characters typed yet but a small pause is required before method being hit.

I want to pause because, as the user types into the search view, a request with the string will be made to server to request the matched data, and then I will populate my ListView according to suggestions.

Activity information (if required) :
Implements SearchView.OnQueryTextListener.

    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView)MenuItemCompat.getActionView(searchItem);
    searchView.setOnQueryTextListener(this);
Shubham A.
  • 2,446
  • 4
  • 36
  • 68
  • no, why do you need that? – pskink May 05 '15 at 08:24
  • You can use a TimerTask to delay filtering your list. Put the code of filtering inside the timer. However I would not recommend delaying search. – Skynet May 05 '15 at 08:28
  • @pskink To fetch data from server as the user types into the SearchView. Request must not be made every time a character is typed, rather, there should be a pause. – Shubham A. May 05 '15 at 08:28
  • @Skynet Please elaborate, why don't you recommend a TimerTask? – Shubham A. May 05 '15 at 08:30
  • use a Filterable interface, please don't reinvent the wheel, you can use FilterQueryProvider for example – pskink May 05 '15 at 08:30
  • I second using a FilterQueryProvider. I said I dont recommend delaying search, you can use a timer task. If you dont want to access the server each time, allow the user to use the submit button of the SearchView. – Skynet May 05 '15 at 08:38
  • @Skynet Why not to delay search? User usually knows what they are searching for (at least in my case, they do). If the search isn't delayed, ListView will get populated with 'S' suggestions, followed by "Sk", "Sky", till "Skynet". Though I know that the past data from ListView can be flushed. – Shubham A. May 05 '15 at 08:43
  • 1
    Seen how Play Store does it - super fast? – Skynet May 05 '15 at 08:48

5 Answers5

39

To delay the call to your server, use the following code in your onQueryTextChange method, the variables mQueryString and mHandler must be class variables. also check mHandler!=null

@Override
public boolean onQueryTextChange(String searchTerm) {
    mQueryString = searchTerm;
    mHandler.removeCallbacksAndMessages(null);

    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
           //Put your call to the server here (with mQueryString)
        }
    }, 300);
    return true;
}
killianke
  • 423
  • 5
  • 9
9

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;
}
C. Hellmann
  • 556
  • 6
  • 13
7

You can use Kotlin coroutines like this. Declare the countdown job

private lateinit var textChangeCountDownJob: Job

And then onQueryTextChange:

    override fun onQueryTextChange(newText: String): Boolean {

        if(::textChangeCountDownJob.isInitialized)
            textChangeCountDownJob.cancel()

        textChangeCountDownJob = launch(UI) {
            delay(800)
        }

        return false
    }
Sukitha Udugamasooriya
  • 2,268
  • 1
  • 35
  • 56
2

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

private long delay = 2000; 
private long editTextLastWord = 0;
privaste  SearchView searchView;
Handler handler = new Handler();

private Runnable runnable = new Runnable() {
    public void run() {
        if (System.currentTimeMillis() > (editTextLastWord + delay - 500)) {

          perFormTask();
        }
    }
};
 searchView=(SearchView) findViewById(R.id.searchView);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
 if (s.length() > 2) {              
          editTextLastWord = System.currentTimeMillis();
          handler.postDelayed(runnable, delay);
        } else {

        }
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
  handler.removeCallbacks(runnable);
            }
        });
Ashutosh Srivastava
  • 597
  • 1
  • 9
  • 13
2

1) Create abstract class:

public abstract class DelayedOnQueryTextListener implements SearchView.OnQueryTextListener {

    private Handler handler = new Handler();
    private Runnable runnable;

    @Override
    public boolean onQueryTextSubmit(String s) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String s) {
        handler.removeCallbacks(runnable);
        runnable = () -> onDelayerQueryTextChange(s);
        handler.postDelayed(runnable, 400);
        return true;
    }

    public abstract void onDelayerQueryTextChange(String query);
}

2) Set it like this:

searchView.setOnQueryTextListener(new DelayedOnQueryTextListener() {
    @Override
    public void onDelayerQueryTextChange(String query) {
        // Handle query
    }
});
Johnny Five
  • 987
  • 1
  • 14
  • 29