2016-03-21 12 views
1

Ich implementiere eine Standortvorschlag Aktivität, die Vorschläge von einem externen Server füllt, wie der Benutzer in einer Textansicht eingibt. Ich verwende eine AsyncTask, um Vorschläge jedes Mal abzurufen, wenn sich der Text in der Textansicht ändert. Wenn ein neuer Brief eingegeben wird, brechen wir die bereits bestehende Aufgabe ab und führen eine neue aus. Die meiste Zeit doInBackground beginnt sofort nach execute wird aufgerufen, aber andere Male kann es ein paar Sekunden dauern. (Once doInBackground beginnt, ist die Leistung in Ordnung.)Android Autocomplete AsyncTask Verzögerung

Set Hörer:

private void init() { 
    // respond to any text change 
    textView.addTextChangedListener(new TextWatcher() { 
     @Override 
     public void onTextChanged(final CharSequence s, int start, int b, int c) { 
      showSuggestions(s.toString()); 
     } 
    }); 
} 

Hier beginnen wir eine neue Aufgabe und kündigen die vorherige:

private void showSuggestions(String query) { 
    // suggestionsTask is an instance variable of the activity 
    if (suggestionsTask != null) { 
     suggestionsTask.cancel(true); 
    } 

    suggestionsTask = new AsyncTask<String, Void, List<Suggestion>>() { 
     @Override 
     protected void onPostExecute(List<Suggestion> resultList) { 
      // set suggestions with adapter - CHANGES STATE 
     } 

     @Override 
     protected List<Suggestion> doInBackground(String... query) { 
      // one local db call for recent searches - DOES NOT CHANGE STATE 
      // one network call to external server - DOES NOT CHANGE STATE 
      // return results 
     } 
    }; 

    suggestionsTask.execute(query); 
} 

Gibt es einen besseren Fädelmechanik zu dafür benutzen? Weißt du warum es eine Verzögerung zwischen execute und doInBackground gibt?

+2

Es könnte sein, dass die Aufgaben serialisiert sind und eine vorherige Aufgabe ihre Zeit zum Abbrechen benötigt. –

+0

Das klingt sehr wahrscheinlich. Hast du eine Idee, wie du das umgehen kannst? – lf215

Antwort

1

Vom AsyncTask reference:

Eine Aufgabe kann durch den Aufruf abzubrechen (boolean) jederzeit abgebrochen werden. Das Aufrufen dieser Methode führt zu nachfolgenden Aufrufen von isCancelled(), um true zurückzugeben. Nach dem Aufruf dieser Methode wird onCancelled (Object) anstelle von onPostExecute (Object) aufgerufen, nachdem doInBackground (Object []) zurückgegeben wurde. Um sicherzustellen, dass eine Aufgabe, so schnell wie möglich aufgehoben wird, können Sie immer den Rückgabewert von isCancelled überprüfen sollten,() periodisch von doInBackground (Object []), wenn möglich (in einer Schleife zum Beispiel.)

Sie brechen also den doInBackground() - Schritt nicht ab, es sei denn, Sie überprüfen manuell, ob isCancelled() in doInBackground regelmäßig gesetzt ist. In den meisten Versionen von Android teilen sich alle AsyncTasks einen einzelnen Thread. Daher muss einer beendet werden, bevor der nächste gestartet werden kann. Das ist also der Grund für Ihre Verzögerung, aber ich habe nicht genügend Informationen (d. H. Sie haben den Code nicht gepostet) aus Ihrem doInBackground() - Code, um einen Vorschlag darüber zu machen, wo nach isCancelled() gesucht werden soll.

Wenn die vorherige Aufgabe in der Lage, nicht möglich, aus irgendeinem Grunde zu kündigen, können Sie auch versuchen, Ihre AsyncTasks parallel ausführen, Einsatz executeOnExecutor(java.util.concurrent.Executor, Object[]) mit THREAD_POOL_EXECUTOR als die gleichen Dokumentation schlägt vor, aber mit dem, was Sie versuchen, das scheint zu tun es könnte einige frustrierende Threading-Probleme verursachen, die wahrscheinlich schlimmer sind als die, die Sie gerade haben.

+0

"... THREAD_POOL_EXECUTOR wie die gleiche Dokumentation vorschlägt, aber mit dem, was Sie versuchen, scheint es einige frustrierende Threading-Probleme zu geben". Wie kann es Threading-Probleme geben, wenn ich vor jeder neuen Ausführung abbrechen und daher nur die letzte Aufgabe onPostExecute ausführt? Mein Beitrag enthält dies nicht, aber ich habe versucht zu implizieren, dass der einzige globale Zustand, der geändert wird, in onPostExecute: "Vorschläge mit Adapter setzen" – lf215

+0

Nun, das einfachste Beispiel ist, wenn Sie mehrere AsyncTasks auf verschiedenen Threads ausführen Es gibt keine Garantie, dass die erste, die du gestartet hast, die erste sein wird, die fertig ist. Sie könnten also von einer langsamen, aber korrekten Lösung zu einer schnelleren, aber falschen Lösung wechseln. Natürlich können Sie den Threadpool-Executor auch weiterhin verwenden, aber es bereitet Probleme, auf die Sie sich nur schwer vorbereiten können, und, noch ärgerlicher, gehen Sie nicht konsequent aus. Es wäre viel einfacher, sich einfach an den Standard-Executor zu halten und sicherzustellen, dass Sie tatsächlich die vorherige Aufgabe mit einer Schleife in doInBackground() beenden, meiner Meinung nach. – ajpolt

+0

Ich stimme Ihnen im allgemeinen Fall zu, aber angesichts des Codes, den ich in die Frage aufgenommen habe, denke ich, dass Ihre Einschätzung hier zu vorsichtig/falsch ist. "Wenn Sie mehrere AsyncTasks auf verschiedenen Threads ausführen, gibt es keine Garantie, dass die erste, die Sie gestartet haben, die erste sein wird." Es ist mir egal, dass die erste beendet wird - nur dass die letzte den Adapter zuletzt ändert. Ich bin offen für die Möglichkeit, dass meine Lösung falsch sein könnte, wenn ich THREAD_POOL_EXECUTOR verwende, aber ich sehe den Beweis in Ihren Kommentaren nicht. Bitte wenden Sie sich an meine frühere Frage: "Wie könnte es sein ... onPostExecute?" – lf215