Async-Task Android ausführen

Dies wurde in einem der Android-Interviews gefragt. Ich wurde gefragt, ob es möglich ist, eine andere asynchische Aufgabe zu starten (lass es Task2 sein) von der doInBackground () Methode der asynchronen Task 1 (lass es Task1 sein). Ich war durch die Docs gegangen, die folgendes sagen:

Die Task-Instanz muss im UI-Thread angelegt werden.

  • Abonnement in-App-Erneuerung in android
  • Javascript im Hintergrund mit Phonegap ausführen
  • Wie bindet man zwei Android Activites an einen Service?
  • Gibt es eine einfache Möglichkeit, ein Action Button Fragment zu erstellen?
  • So stellen Sie den Text ein, um aus dem Schubladen-Header-Layout in der Navigationsschublade ohne Aufblasansicht zu sehen
  • Ausführung fehlgeschlagen für Task ': app: compileDebugNdk'
  • Execute (Params …) muss auf dem UI-Thread aufgerufen werden.

    Nach diesen Aussagen denke ich, dass es nicht möglich sein sollte, eine Aufgabe aus der Hintergrundmethode einer anderen Aufgabe zu starten. Auch async-Task hat UI-Methoden (die nicht auf einem Hintergrund-Thread verwendet werden können), so dass mein Argument gestärkt und ich antwortete es als nicht möglich.

    Bei der Überprüfung einer einfachen Demo-App habe ich gesehen, dass es in der Tat möglich ist, dies zu tun. Einige Demo-Code:

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; init(); Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName()); Task1 task = new Task1(); task.execute(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 started"); return null; } } 

    Ich bekomme folgende Protokolle, die auf eine erfolgreiche Ausführung hindeuten:

     > 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07 > 09:46:25.564: V/gaurav(2100): Task 2 started 

    Ich habe das auf ICS, KK und L Gerät überprüft und es funktioniert gut für alle.

    Ein Grund, den ich mir vorstellen konnte, ist, dass ich keine UI-Methoden überschreibe und irgendeine UI-Aktualisierung in meiner zweiten Aufgabe mache, daher verursacht es keine Probleme, aber ich bin mir nicht sicher. Auch wenn das der Fall ist, verletzt es die Threading-Regeln, die in der Entwickler-Guide erwähnt werden.

    Als Referenz habe ich auch diesen Link ausgecheckt : Starten Sie AsyncTask aus einer anderen AsyncTask doInBackground (), aber die Antwort sagt, um die zweite Task mit runOnUiThread () Methode in doInBackground () zu starten. Ich würde gern etwas davon machen, was hier los ist. Vielen Dank.

  • Schütteln Sie das Gerät, um eine Anwendung in Android zu starten
  • Wie kann man die Haufengröße einer Android-Anwendung erhöhen?
  • Wie man HTTP-Anfragen über WiFi direkt aus Android Wear?
  • Decodieren von Airplay-Paketen in Java oder C / C ++ auf Android
  • Zeigen Sie eine Softtastatur für die Aktivierung der Suchleiste mit SearchView
  • Wie bekomme ich einen EditText?
  • One Solution collect form web for “Async-Task Android ausführen”

    Lassen Sie uns Ihren Code wie folgt ändern:

     class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.v ("gaurav", "Log after sleeping"); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 Started"); return null; } } 

    Jetzt kehrt der LogCat zurück:

     08-07 06:13:44.208 3073-3073/testapplication V/gaurav﹕ Thread is : main 08-07 06:13:44.209 3073-3091/testapplication V/gaurav﹕ Thread task 1 is : AsyncTask #1 08-07 06:13:49.211 3073-3091/testapplication V/gaurav﹕ Log after sleeping 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Thread task 2 is : AsyncTask #2 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Task 2 Started 

    Wie Sie sehen können, wird die Task 2 nach dem Ende der Task 1 Ausführung ausgeführt (auch nach dem Einschlafen für 5 Sekunden). Es bedeutet, dass die zweite Aufgabe nicht gestartet wird, bis die erste Aufgabe ist.

    Warum? Der Grund liegt hinter dem Quellcode von AsyncTask . Bitte beachten Sie die execute() Methode:

     public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } 

    Und scheduleNext() -Methode:

     protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } 

    Das wichtigste Keyword in diesen Methoden ist synchronized das sicherstellt, dass diese Methoden nur in einem Thread gleichzeitig ausgeführt werden. Wenn du die execute Methode Runnable , bietet es eine neue Runnable zu mTask die eine Instanz von ArrayDeque<Runnable> Klasse ist, die als Serializer der verschiedenen Anfragen an verschiedenen Threads arbeitet [mehr Infos] . Wenn es keine ausgeführte Runnable (dh if (mActive == null) ), würde das scheduleNext() aufgerufen werden, andernfalls würde das scheduleNext() im finally Block nach dem (aus irgendeinem Grund) Ende des laufenden ausgeführten Runnable . Alle Runnable s werden auf einem separaten Thread von THREAD_POOL_EXECUTOR .

    Was ist los mit der Ausführung von AsyncTask aus anderen Threads? Beginnend mit Jelly Bean, wird eine AsyncTask beim Applikationsstart auf dem UI-Thread klassenklassen, so dass die Rückrufe im UI-Thread sichergestellt sind, jedoch vor der Jelly Bean-Version, falls ein weiterer Thread die AsyncTask erstellt, AsyncTask die Rückrufe erfolgen Nicht auf dem richtigen Thread auftreten.

    Also, AsyncTask Implementierungen sollten aus dem UI-Thread nur auf Plattformen vor Jelly Bean ( + und + ) aufgerufen werden.


    Klarstellung: Bitte beachten Sie das folgende Beispiel, das einfach die Unterschiede zwischen den verschiedenen Plattform-Releases von Android verdeutlicht:

     protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); new Thread() { @Override public void run() { Task1 task = new Task1(); task.execute(); } }.start(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { return null; } } 

    Es funktioniert gut auf Android 5.1, aber stürzt mit der folgenden Ausnahme auf Android 2.3:

     08-07 12:05:20.736 584-591/github.yaa110.testapplication E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-8 java.lang.ExceptionInInitializerError at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21) Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:121) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask.<clinit>(AsyncTask.java:152)            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21) 
    Das Android ist ein Google Android Fan-Website, Alles über Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.