Android: Как отправлять запросы в API Google, когда пользователь делает паузу?

Я работаю над этим приложением, где пользователи могут вводить местоположение в autoCompleteTextView, и он предлагает местоположения на основе Google Places Api, как описано здесь.

Однако я хотел бы ограничить объем отправки запроса приложением, отправив запросы только в том случае, если пользователь перестает печатать на определенное количество времени. Кто-нибудь знает, как это сделать?

Ответ 1

Я нашел решение этой проблемы, которая работает довольно хорошо. Я расширил AutoCompleteTextView следующим образом. Если кто-то знает, как улучшить код, пожалуйста, дайте мне знать.

public class MyAutoCompleteTextView extends AutoCompleteTextView {

// initialization
int threshold;
int delay = 750;
Handler handler = new Handler();
Runnable run;

// constructor
public MyAutoCompleteTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected void performFiltering(final CharSequence text, final int keyCode) {
    // get threshold
    threshold = this.getThreshold();

    // perform filter on null to hide dropdown
    doFiltering(null, keyCode);

    // stop execution of previous handler
    handler.removeCallbacks(run);

    // creation of new runnable and prevent filtering of texts which length
    // does not meet threshold
    run = new Runnable() {
        public void run() {
            if (text.length() > threshold) {
                doFiltering(text, keyCode);
            }
        }
    };

    // restart handler
    handler.postDelayed(run, delay);
}

// starts the actual filtering
private void doFiltering(CharSequence text, int keyCode) {
    super.performFiltering(text, keyCode);
}

}

Ответ 2

Как и этот ответ, но немного более кратким и без введения дополнительного состояния. Вам также не нужны проверки порога, так как performFiltering вызывается только тогда, когда фактически требуется фильтрация.

Подклассификация AutoCompleteTextView кажется единственным способом, так как вы не можете переопределить/заменить TextWatcher, добавленный AutoCompleteTextView.

public class DelayAutoCompleteTextView extends AutoCompleteTextView {           
    public DelayAutoCompleteTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            DelayAutoCompleteTextView.super.performFiltering((CharSequence) msg.obj, msg.arg1);
        }
    };

    @Override
    protected void performFiltering(CharSequence text, int keyCode) {
        mHandler.removeMessages(0);
        mHandler.sendMessageDelayed(mHandler.obtainMessage(0, keyCode, 0, text), 750);
    }
}

Ответ 3

Вы можете использовать TextWatcher и контролировать, сколько времени между текстовыми записями. Мне лично не нравится идея подклассификации собственных элементов управления Android (хотя это, безусловно, действительный подход, а не мой предпочтительный подход).

Документы: http://developer.android.com/reference/android/text/TextWatcher.html

и ссылка SO: Как использовать класс TextWatcher в Android?

Ответ 4

Как и в ответах выше, я обнаружил, что мне нужно подклассировать AutoCompleteTextView. Однако, поскольку в Интернете я немного медленный, я обнаружил, что удаление обработчиков с задержкой каждый раз, когда пользователь нажал клавишу, был проблемой. Так что, если я только запускаю фильтр, возможно, 500 мс после того, как пользователь перестанет печатать, может потребоваться несколько секунд, чтобы результаты появлялись, что сделало бы пользователя раздраженным.

Поэтому вместо этого я не очищаю обработчик каждый раз, и пусть фильтрация запускается каждые пару сотен мс. Мой код гораздо менее чистый Ян Беркель. Я уверен, что вы можете немного почистить его, я слишком ленив, но производительность лучше в областях с медленным интернет-ИМО.

public class CustomCompleteView extends AutoCompleteTextView{

Handler handler=new Handler();
Runnable r;
boolean cleartogo=false;
boolean pending =false;
CharSequence btext; 
int bkeyCode;
public CustomCompleteView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
}

public CustomCompleteView(Context context, AttributeSet attrs)
{
    super(context,attrs);
}
public CustomCompleteView(Context context, AttributeSet attrs, int defStyle)
{
    super(context,attrs,defStyle);
}

@Override
public void performFiltering(CharSequence text, int keyCode){
    if (cleartogo){
        cleartogo=false;
        Log.d(MainActivity.DTAG,"Going to filter on " + text.toString());
        pending=false;
        super.performFiltering(btext, bkeyCode);
    }
    else
    {
        Log.d(MainActivity.DTAG,"Filtering rejected, too soon");
        btext=text;
        bkeyCode=keyCode;
        if (!pending){
        if (r==null)
            r=new MyRunnable(this);
        //try{handler.removeCallbacks(r);} catch (Exception ex){};
        handler.postDelayed(r, 500);
        pending=true;}
    }

}

private class MyRunnable implements Runnable {


CustomCompleteView bc;


    MyRunnable(CustomCompleteView c ) {
        this.bc=c;

    }

    public void run() {
        Log.d(MainActivity.DTAG,"Special Runnable running");
        cleartogo=true;
        bc.performFiltering(btext, bkeyCode);


    }
}

}