AutoCompleteTextView не отображает результат, даже когда обновляется ArrayAdapter - PullRequest
7 голосов
/ 20 апреля 2010

Я пытаюсь получить AutoCompleteTextView (ACTV) для отображения результатов, которые я получаю от сетевого ресурса. Я установил порог завершения на 2 и вижу, что запрос запускается при вводе символов.

Результат, который я получаю, правильный. Допустим, я пишу «ca», и я получаю результат «car» как автозаполнение. У меня есть функция обратного вызова, которая получает результат от AsyncTask и помещает результат в ArrayAdapter. Затем я вызываю .showDropDown () на ACTV, и отображается пустой выпадающий список (половина размера обычного элемента). Затем, если я введу последнюю букву «r», и ACTV покажет «автомобиль», появится раскрывающийся список, и результат внезапно окажется в списке.

То же самое происходит, если я ввел два символа (которые возвращают действительный результат) и удалил последнюю букву. Когда буква удалена, в качестве значения автозаполнения отображается «автомобиль».

У кого-нибудь была эта проблема? Похоже, что адаптер заполнен результатом, но результат не отображается до следующего действия, которое я делаю. Я также попытался запустить .notifyDataSetChanged () после того, как добавил результат в адаптер, но это не нужно, или?

Ответы [ 2 ]

16 голосов
/ 25 апреля 2010

Не видя ваш код, трудно сказать, что может происходить. Но первое, что приходит на ум, это то, что ваш сетевой запрос выполняется в другом потоке, и поэтому ваш performFiltering() может возвращать пустой набор результатов преждевременно. В этот момент publishResults() возвращает пустой результат, и ваш выпадающий список пуст. Позже ваш AsyncTask вернет свой результат, и вы добавите результаты в список адаптера, но по тем или иным причинам он еще не отображается.

Я думаю, что вы можете ошибаться по поводу необходимости AsyncTask. Объект Filter уже выполняет что-то похожее на AsyncTask: performFiltering() выполняется в фоновом потоке, а publishResults() вызывается из потока пользовательского интерфейса после выполнения executeFiltering (). Таким образом, вы можете выполнить сетевой запрос непосредственно в executeFiltering () и установить результаты в объекте FilterResults, и вам не придется беспокоиться о том, что сетевой запрос слишком медленный и вызывает проблемы в вашем пользовательском интерфейсе.

Альтернативное решение, которое немного сложнее, но это то, что я делаю в своем объекте Filter (из-за существующей архитектуры, которая выполняет вызовы API в фоновом режиме, используя асинхронный обратный вызов вместо блокирующего / синхронного шага, как требуется) for executeFiltering ()) - использовать синхронизированный объект с wait () / notify () для выполнения многопоточного мониторинга, поэтому эффект такой же, как выполнение сетевого запроса непосредственно в executeFiltering (), но на самом деле это происходит в нескольких темы:

// in Filter class..
protected FilterResults performFiltering(CharSequence constraint) {

    APIResult response = synchronizer.waitForAPI(constraint);
    // ...
}

// callback invoked after the API call finishes:
public void onAPIComplete(APIResult results) {
    synchronizer.notifyAPIDone(results);
}

private class Synchronizer {
    APIResult result;

    synchronized APIResult waitForAPI(CharSequence constraint) {
        someAPIObject.startAsyncNetworkRequest(constraint);
        // At this point, control returns here, and the network request is in-progress in a different thread.
        try {
            // wait() is a Java IPC technique that will block execution until another
            // thread calls the same object's notify() method.
            wait();
            // When we get here, we know that someone else has just called notify()
            // on this object, and therefore this.result should be set.
        } catch(InterruptedException e) { }
        return this.result;
    }

    synchronized void notifyAPIDone(APIResult result) {
        this.result = result;
        // API result is received on a different thread, via the API callback.
        // notify() will wake up the other calling thread, allowing it to continue
        // execution in the performFiltering() method, as usual.
        notify();
    }
}

Тем не менее, я думаю, что вы можете обнаружить, что самое простое решение - просто выполнить ваш сетевой запрос синхронно, прямо в методе executeFiltering (). Приведенный выше пример кода - это всего лишь одна из возможностей, если у вас уже есть архитектура для API-вызовов, управляемых асинхронными / обратными вызовами, и вы не хотите изменять это поведение, чтобы получить синхронные результаты в executeFiltering ().

1 голос
/ 16 ноября 2015

Я думаю, что ответ Джо - путь. Тем не менее, я думаю, что вы должны использовать CountDownLatch вместо ожидания / уведомления.

Причина в том, что при ожидании / уведомлении вы рискуете состоянием гонки, если ваш API действительно очень быстро возвращается, прежде чем вы начнете "wait ()" ... в этом случае уведомление не будет иметь эффекта, а wait () будем ждать до бесконечности. С Latch код будет выглядеть так (скопировано с Джо и изменено):

// in Filter class..
protected FilterResults performFiltering(CharSequence constraint) {
  APIResult response = synchronizer.waitForAPI(constraint);
  // ...
}

// callback invoked after the API call finishes:
public void onAPIComplete(APIResult results) {
  synchronizer.notifyAPIDone(results);
}

private class Synchronizer {
  APIResult result;
  CountDownLatch latch;

  synchronized APIResult waitForAPI(CharSequence constraint) {
      latch = new CountDownLatch(1);
      someAPIObject.startAsyncNetworkRequest(constraint);
      // At this point, control returns here, and the network request is in-progress in a different thread.
      try {
        // Will wait till the count is 0...
        // If the count is already 0, it'll return immediately. 
        latch.await();
        // When we get here, we know that someone else has just called notify()
        // on this object, and therefore this.result should be set.
    } catch(InterruptedException e) { }
    return this.result;
  }

  synchronized void notifyAPIDone(APIResult result) {
    this.result = result;
    // API result is received on a different thread, via the API callback.
    // countDown() will wake up the other calling thread, allowing it to continue
    // execution in the performFiltering() method, as usual.
    latch.countDown();
  }
}

Наконец, у меня недостаточно средств для публикации комментария, иначе я бы получил ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...