Frage

Ich versuche, eine AutoCompleteTextView (ACTV) zu Anzeige Ergebnisse zu erhalten Ich bin ein von einer Netzwerk-Ressource zu bekommen. Ich habe den Abschluss-treshold auf 2 gesetzt, und ich kann sehen, dass die Anforderung ausgelöst, wenn ich Zeichen eingegeben werden.

Das Ergebnis erhalte ich die richtige ist. Sagen wir ich „ca“ schreiben, und ich das Ergebnis „Auto“ als Auto-Vervollständigung erhalten. Ich habe eine Callback-Funktion, die das Ergebnis von einem AsyncTask empfängt und legt das Ergebnis in die ArrayAdapter. Dann rufe ich .showDropDown () auf der ACTV und ein leeres Dropdown angezeigt wird (die Hälfte der Größe eines normalen Element). Dann, wenn ich die letzten Buchstaben „r“ und die ACTV zeigt „Auto“ eingeben, wird die Drop-Down gezeigt und das Ergebnis ist plötzlich in der Liste.

Das gleiche passiert, wenn ich zwei Zeichen eingegeben haben (die ein gültiges Ergebnis zurückgibt), und das Entfernen Sie den letzten Buchstaben. Wenn der Brief entfernt wird, „Auto“ als Auto-Vervollständigung Wert gezeigt.

Hat jemand dieses Problem gehabt? Es sieht aus wie der Adapter mit dem Ergebnis, gefüllt ist, aber das Ergebnis zeigt nicht bis zur nächsten Aktion, die ich tue. Ich habe auch zu laufen .notifyDataSetChanged versucht (), nachdem ich das Ergebnis an den Adapter hinzugefügt habe, aber das sollte nicht nötig sein, oder?

War es hilfreich?

Lösung

Ohne Code zu sehen, ist es schwer zu sagen, was könnte gehen. Aber das erste, was in den Sinn kommt, ist, dass Ihr Netzwerk Anfrage auf einem anderen Thread geschieht, und somit Ihre performFiltering() kann ein leeres Resultset vorzeitig zurückkehren. An diesem Punkt kehrt publishResults() das leere Ergebnis und Ihr Drop-Down ist leer. Später Ihre AsyncTask wird sein Ergebnis zurück, und Sie die Ergebnisse in der Liste der Adapter hinzufügen, aber für einen oder anderen Grund, ist es noch nicht angezeigt bekommen.

Ich glaube, Sie über die Notwendigkeit AsyncTask verwechselt werden können though. Das Filter-Objekt tut schon etwas ähnliches wie AsyncTask: performFiltering() wird in einem Hintergrund-Thread getan, und publishResults() wird aus dem UI-Thread aufgerufen, nachdem performFiltering () beendet ist. So können Sie Ihre Netzwerkanfrage direkt in performFiltering () tun können, und die Ergebnisse in die FilterResults gesetzt Objekt, und Sie werden sich keine Sorgen über die Netzwerkanforderung zu langsam zu sein haben und verursacht Probleme in Ihrer Benutzeroberfläche.

Eine alternative Lösung, die etwas komplizierter ist, aber es ist, was ich in meinem Filter-Objekt zu tun (wegen Architektur bestehenden, die API-Aufrufe im Hintergrund tut, einen asynchronen Rückruf anstelle des Sperr / Synchron nach Bedarf für performFiltering ()) ist ein synchronisiertes Objekt mit wait () verwenden / notify () für die Querfadenüberwachung zu tun, so dass der Effekt der gleiche ist, um die Netzwerkanforderung direkt in performFiltering () als zu tun, aber es geschieht tatsächlich in mehreren Themen:

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

Aber ich denke, Sie werden feststellen, dass die einfachste Lösung ist, einfach synchron Ihr Netzwerk Anforderung zu tun, direkt in dem performFiltering () -Methode. Das obige Codebeispiel ist nur eine Möglichkeit, wenn Sie bereits die Architektur an den richtigen Stelle für asynchrone / Callback-driven-API-Aufrufe, und Sie wollen nicht, dass das Verhalten ändern, um synchrone Ergebnisse in performFiltering () zu erhalten.

Andere Tipps

Ich denke, Joe Antwort ist der Weg zu gehen. Aber ich denke, Sie verwenden sollten CountDownLatch anstelle von Warte / benachrichtigen.

Der Grund dafür ist, mit Warte / benachrichtigen, riskieren Sie eine Race-Bedingung, wenn Ihr API tatsächlich super schnell zurück, bevor Sie „wait ()“ ... in diesem Fall starten, benachrichtigen wird keine Wirkung und warten () wartet auf unbestimmte Zeit. Mit Latch, sieht der Code wie folgt (von Joe kopiert und geändert):

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

Schließlich habe ich nicht genug Kredit um einen Kommentar zu posten, sonst hätte ich ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top