AutoCompleteTextView No visualizando el resultado, incluso cuando se actualiza el ArrayAdapter

StackOverflow https://stackoverflow.com/questions/2671404

Pregunta

Estoy tratando de obtener una AutoCompleteTextView (ACTV) para mostrar los resultados que estoy obteniendo una desde un recurso de red. Yo he dado la finalización-umbral a 2 y puedo ver que la solicitud se dispara cuando entro a caracteres.

El resultado que estoy recibiendo es la correcta. Digamos que escribo "ca", y consigo el "coche" de resultado como una terminación automática. Tengo una función de devolución de llamada que recibe el resultado de una AsyncTask y pone el resultado en el ArrayAdapter. Entonces llamo .showDropDown () en el ACTV y un desplegable vacío se muestra (la mitad del tamaño de un elemento normal). A continuación, si entro en la última letra "r" y el "coche" muestra ACTV, se muestra el menú desplegable y el resultado es de repente en la lista.

Lo mismo ocurre si he entrado dos personajes (que devuelve un resultado válido), y el quitar la última letra. Cuando se retira la carta, "coche" se muestra como un valor de terminación automática.

¿Alguien ha tenido este problema? Parece que el adaptador se llena con el resultado, pero el resultado no aparece hasta que la siguiente acción que hago. También he probado para funcionar .notifyDataSetChanged () después de haber añadido el resultado al adaptador, pero eso no debería ser necesario, o?

¿Fue útil?

Solución

Sin ver su código, es difícil saber lo que podría estar sucediendo. Pero la primera cosa que viene a la mente es que su solicitud de red está sucediendo en un hilo diferente, y por lo tanto su performFiltering() puede devuelve un conjunto de resultados vacío antes de tiempo. En ese momento, publishResults() está devolviendo el resultado vacío, y el desplegable está vacía. Más tarde, su AsyncTask tendrá su posterior resultado, y añadir los resultados en la lista del adaptador, pero por una razón u otra, no va a ser visualizado todavía.

Creo que puede ser confundido acerca de la necesidad de AsyncTask sin embargo. El objeto de filtro ya está haciendo algo similar a AsyncTask: performFiltering() se realiza en un subproceso en segundo plano, y publishResults() se llama desde el subproceso de interfaz de usuario, después de performFiltering () está terminado. Lo que puede hacer su solicitud directamente a la red en performFiltering (), y establecer los resultados en las FilterResults objeto, y no tendrá que preocuparse acerca de la solicitud de red es demasiado lenta y causando problemas en la interfaz de usuario.

Una solución alternativa, que es un poco más complicado, pero es lo que estoy haciendo en mi filtro de objetos (debido a la arquitectura que hace llamadas a la API en el fondo existente, utilizando una devolución de llamada asincrónica en lugar de la etapa de bloqueo / síncrono según sea necesario para performFiltering ()), es utilizar un objeto sincronizado con wait () / notify () para hacer el monitoreo entre subprocesos, por lo que el efecto es el mismo que hacer la solicitud de red directamente en performFiltering (), pero en realidad está sucediendo en múltiples hilos:

// 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();
    }
}

Sin embargo, creo que es posible que la solución más fácil es que acaba de hacer su solicitud a la red de forma sincrónica, situado en el método performFiltering (). El ejemplo de código anterior es sólo una posibilidad, si ya tiene la arquitectura en lugar de asíncrono / devolución de llamada impulsada por llamadas a la API, y usted no quiere cambiar ese comportamiento con el fin de obtener resultados sincrónicos en performFiltering ().

Otros consejos

Creo que la respuesta de Joe es el camino a seguir. Sin embargo, creo que se debe usar CountDownLatch en lugar de esperar / notificación.

La razón es, con / notificar, se arriesga a una condición de carrera, espere Si la API vuelven en realidad super rápida antes de empezar "wait ()" ... en este caso, notificar no tendrá un efecto y wait () esperará indefinidamente. Con el cierre, el código se verá así (copiado de Joe y modificado):

// 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();
  }
}

Por último, no tengo crédito suficiente para publicar un comentario, de lo contrario tendría ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top