Die AsyncTask-API ist in Android 11 veraltet. Welche Alternativen gibt es?

Lesezeit: 11 Minuten

Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
Zeeshan

Google lehnt die Android AsyncTask-API in Android 11 ab und schlägt die Verwendung vor java.util.concurrent stattdessen. Sie können sich das Commit ansehen Hier

 *
 * @deprecated Use the standard <code>java.util.concurrent</code> or
 *   <a href="https://developer.android.com/topic/libraries/architecture/coroutines">
 *   Kotlin concurrency utilities</a> instead.
 */
@Deprecated
public abstract class AsyncTask<Params, Progress, Result> {

Wenn Sie eine ältere Codebasis mit asynchronen Aufgaben in Android pflegen, müssen Sie diese wahrscheinlich in Zukunft ändern. Meine Frage ist, was der richtige Ersatz des unten gezeigten Code-Snippets sein sollte java.util.concurrent. Es ist eine statische innere Klasse einer Aktivität. Ich suche etwas, womit es funktioniert minSdkVersion 16

private static class LongRunningTask extends AsyncTask<String, Void, MyPojo> {
        private static final String TAG = MyActivity.LongRunningTask.class.getSimpleName();
        private WeakReference<MyActivity> activityReference;

        LongRunningTask(MyActivity context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected MyPojo doInBackground(String... params) {
            // Some long running task
            
        }

        @Override
        protected void onPostExecute(MyPojo data) {

            MyActivity activity = activityReference.get();
            activity.progressBar.setVisibility(View.GONE);
            populateData(activity, data) ;
        }     


    }

  • “Veraltet” bedeutet, dass Google Ihnen empfiehlt, zu etwas anderem zu wechseln. Dies bedeutet nicht, dass die Klasse in absehbarer Zeit entfernt wird. Bestimmtes, AsyncTask kann nicht entfernt werden, ohne die Abwärtskompatibilität zu beeinträchtigen.

    – CommonsWare

    8. November 2019 um 13:52 Uhr

  • @ Style-7 ist es nicht.

    – EpicPandaForce

    8. November 2019 um 14:55 Uhr

  • Das ist ein Desaster. Es wird empfohlen zu verwenden AsyncTask aus dem offiziellen Android-Dokument. Ich war ein Backend-Entwickler und bereits mit dem executorService vertraut. Für diese Empfehlung habe ich alle Hintergrundaufgaben zur Verwendung migriert AsyncTask. Und jetzt sagen sie uns, wir sollen es nicht benutzen?

    – Kimi Chiu

    9. Mai 2021 um 6:35 Uhr

  • @Duna: Hast du irgendwelche Beispiele? Sie löschen veraltete Methoden aus Bibliotheken, da Entwickler die von ihnen verwendeten Bibliotheksversionen kontrollieren. Aber wie ich schon bemerkt habe, AsyncTask kann nicht entfernt werden, ohne die Abwärtskompatibilität zu beeinträchtigen.

    – CommonsWare

    12. August 2021 um 18:41 Uhr

  • @Addy: Das spezifische Anliegen, das ich hier kommentiert habe, ist AsyncTask Sein gelöscht, und das kann nicht passieren, ohne viele vorhandene Apps zu beschädigen. Programmierer sollten andere Techniken lernen als AsyncTask (RxJava, Kotlin-Koroutinen usw.), einfach weil sie besser sind und derzeit in professionellen Umgebungen häufiger verwendet werden.

    – CommonsWare

    24. November 2021 um 12:05 Uhr

1646102830 196 Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
EpicPandaForce

private WeakReference<MyActivity> activityReference;

Gute Befreiung, dass es veraltet ist, weil die WeakReference<Context> war immer ein Hack und keine richtige Lösung.

Jetzt haben die Leute die Möglichkeit, ihren Code zu bereinigen.


AsyncTask<String, Void, MyPojo> 

Basierend auf diesem Code, Progress wird eigentlich nicht benötigt, und es gibt eine String Eingang + MyPojo Ausgang.

Dies ist eigentlich ganz einfach ohne Verwendung von AsyncTask zu bewerkstelligen.

public class TaskRunner {
    private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
    private final Handler handler = new Handler(Looper.getMainLooper());

    public interface Callback<R> {
        void onComplete(R result);
    }

    public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
        executor.execute(() -> {
            final R result = callable.call();
            handler.post(() -> {
                callback.onComplete(result);
            });
        });
    }
}

Wie übergebe ich den String? So:

class LongRunningTask implements Callable<MyPojo> {
    private final String input;

    public LongRunningTask(String input) {
        this.input = input;
    }

    @Override
    public MyPojo call() {
        // Some long running task
        return myPojo;
    }
}

Und

// in ViewModel
taskRunner.executeAsync(new LongRunningTask(input), (data) -> {
    // MyActivity activity = activityReference.get();
    // activity.progressBar.setVisibility(View.GONE);
    // populateData(activity, data) ;

    loadingLiveData.setValue(false);
    dataLiveData.setValue(data);
});

// in Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main_activity);

    viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
    viewModel.loadingLiveData.observe(this, (loading) -> {
        if(loading) {
            progressBar.setVisibility(View.VISIBLE);
        } else {
            progressBar.setVisibility(View.GONE);
        }
    });

    viewModel.dataLiveData.observe(this, (data) -> {
        populateData(data);
    }); 
}

In diesem Beispiel wurde ein Single-Thread-Pool verwendet, der sich gut für DB-Schreibvorgänge (oder serialisierte Netzwerkanforderungen) eignet. Wenn Sie jedoch etwas für DB-Lesevorgänge oder mehrere Anforderungen benötigen, können Sie die folgende Executor-Konfiguration in Betracht ziehen:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

  • Ich erhalte eine Fehlermeldung executor.post. Methode kann nicht aufgelöst werden

    – Kris B

    9. November 2019 um 0:37 Uhr

  • @KrisB anscheinend heißt es execute() anstatt post()

    – EpicPandaForce

    9. November 2019 um 11:14 Uhr

  • newSingleThreadExecutor ist besser zum schreiben, aber das sollte man unbedingt nutzen THREAD_POOL_EXECUTOR am Ende des Beitrags für Datenbanklesevorgänge.

    – EpicPandaForce

    11. November 2019 um 1:08 Uhr

  • Ich habe dieses Beispiel sehr geschätzt. Danke! Am Ende habe ich dies fast genau so verwendet, wie es ist. Ich habe eine static Executor, wie Sie ihn ganz am Ende in Ihrem Codebeispiel gezeigt haben, aber immer noch verwendet werden Executors.newSingleThreadExecutor().

    – dontangg

    24. Juni 2020 um 22:56 Uhr

  • Wenn Sie eine Stornierung benötigen, müssen Sie anstelle von executor.execute executor.submit verwenden und die Zukunft stornieren. baeldung.com/java-future

    – EpicPandaForce

    25. Juni 2020 um 10:40 Uhr

Erstellen einer Schaltflache in der Android Toolbar
Kaschfa Khan

Sie können direkt verwenden Executors von java.util.concurrent Paket.

Ich habe auch danach gesucht und darin eine Lösung gefunden Android Async API ist veraltet Post.

Leider verwendet der Beitrag Kotlin, aber nach ein wenig Mühe habe ich es in Java konvertiert. Hier ist also die Lösung.

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(new Runnable() {
    @Override
    public void run() {

        //Background work here

        handler.post(new Runnable() {
            @Override
            public void run() {
                //UI Thread work here
            }
        });
    }
});

Ziemlich einfach oder? Sie können es etwas mehr vereinfachen, wenn Sie Java 8 in Ihrem Projekt verwenden.

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(() -> {
    //Background work here
    handler.post(() -> {
        //UI Thread work here
    });
});

Dennoch kann es die Kotlin-Begriffe der Prägnanz des Codes nicht schlagen, aber besser als die vorherige Java-Version.

Ich hoffe, das wird Ihnen helfen. Danke

  • Eigentlich können Sie noch einen Schritt nach unten gehen: Executors.newSingleThreadExecutor().execute(() -> dao.insert(data));

    – arun

    9. August 2021 um 0:23 Uhr

  • Danke dafür! Es hat mir beim Aufrufen von Server-API-Aufrufen sehr geholfen. Aber was ist, wenn ich einige Aktualisierungsfortschrittsbalken anzeigen möchte? Wo kann ich den onProgressUpdate-Teil platzieren?

    – Kroi

    7. November 2021 um 13:38 Uhr

1646102830 167 Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
mayank1513

Eine der einfachsten Alternativen ist die Verwendung Thread

new Thread(new Runnable() {
    @Override
    public void run() {
        // do your stuff
        runOnUiThread(new Runnable() {
            public void run() {
                // do onPostExecute stuff
            }
        });
    }
}).start();

Wenn Ihr Projekt unterstützt JAVA8können Sie verwenden lambda:

new Thread(() -> {
    // do background stuff here
    runOnUiThread(()->{
        // OnPostExecute stuff here
    });
}).start();

  • Wie wird der Prozentsatz angezeigt, wenn Hintergrundinformationen aufgerufen werden?

    – Ahamadullah Saikat

    3. Oktober 2020 um 12:16 Uhr

  • Sie müssen runOnUiThread verwenden, um Ihren Fortschrittsbalken oder einen anderen Mechanismus zu aktualisieren, den Sie zum Aktualisieren / Anzeigen von % der abgeschlossenen Aufgabe verwenden.

    – mayank1513

    3. Oktober 2020 um 13:17 Uhr

  • Diese Lösung hat mehrere Nachteile. Erstens behält der Thread einen Verweis auf die Aktivität, dies könnte den Kontext verlieren und die App zum Absturz bringen. Zweitens können wir dies nicht aus einem Fragment verwenden. Drittens können wir den Fortschritt der Hintergrundaufgabe nicht aktualisieren. Viertens gibt es keine Möglichkeit, den Thread abzubrechen. Schließlich erstellt es viele Boilerplate-Codes in der App.

    – Sohn Truong

    21. November 2020 um 5:53 Uhr

  • Ihr Code wird nicht einmal kompiliert …. Ich denke, es sind einige Tippfehler drin, zum Beispiel, wenn Sie sagen new Runnable({...}) was meinen Sie new Runnable(){...}. Denn der erste ist so, als würden Sie einen Konstruktor aufrufen und einen Array-Initialisierer übergeben, wodurch ein Compilerfehler ausgelöst wird. Der zweite ist der richtige Weg, um anonyme innere Klassen zu erstellen

    – Adam Burley

    29. Januar 2021 um 0:37 Uhr

  • @SonTruong Ich habe ein paar echte Fragen zu diesen Nachteilen. 1: Wie/Warum behält der Thread eine Referenz der Aktivität, wenn sie nicht ausdrücklich übergeben wird? ich verstehe runOnUiThread, aber für kurze Aufgaben sollte das kein Problem sein, oder? 3: Kann der Fortschritt der Hintergrundaufgabe nicht einfach durch einen entsprechenden Aufruf innerhalb behandelt werden runOnUiThreadso wie publishProgress/onProgressionUpdate? 4: Abstieg AsyncTask und FutureTask Code, alles, was es tut, ist die Verwendung der Thread.interrupt Funktionalität zum Erstellen der cancel Funktionalität. Wäre es nicht möglich, dasselbe mit diesem Ansatz zu tun?

    – Benjamin Basmaci

    11. August 2021 um 14:12 Uhr

1646102831 933 Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
Sergej

Entsprechend der Android-Dokumentation AsyncTask war veraltet API-Level 30 und es wird empfohlen, die zu verwenden Standard java.util.concurrent oder Kotlin-Parallelitätsdienstprogramme stattdessen.

Mit letzterem kann es ziemlich einfach erreicht werden:

  1. Erstellen Sie eine generische Erweiterungsfunktion an CoroutineScope:

     fun <R> CoroutineScope.executeAsyncTask(
             onPreExecute: () -> Unit,
             doInBackground: () -> R,
             onPostExecute: (R) -> Unit
     ) = launch {
         onPreExecute() // runs in Main Thread
         val result = withContext(Dispatchers.IO) { 
             doInBackground() // runs in background thread without blocking the Main Thread
         }
         onPostExecute(result) // runs in Main Thread
     } 
    
  2. Verwenden Sie die Funktion mit jedem CoroutineScope:

    • Im ViewModel:

      class MyViewModel : ViewModel() {
      
          fun someFun() {
              viewModelScope.executeAsyncTask(onPreExecute = {
                  // ... runs in Main Thread
              }, doInBackground = {
                  // ... runs in Worker(Background) Thread
                  "Result" // send data to "onPostExecute"
              }, onPostExecute = {
                  // runs in Main Thread
                  // ... here "it" is the data returned from "doInBackground"
              })
          }
      }
      
    • Im Activity oder Fragment:

      lifecycleScope.executeAsyncTask(onPreExecute = {
          // ... runs in Main Thread
      }, doInBackground = {
          // ... runs in Worker(Background) Thread
          "Result" // send data to "onPostExecute"
      }, onPostExecute = {
          // runs in Main Thread
          // ... here "it" is the data returned from "doInBackground"
      })
      

    Benutzen viewModelScope oder lifecycleScope fügen Sie die nächste(n) Zeile(n) zu den Abhängigkeiten der App hinzu build.gradle Datei:

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
    

    Zum Zeitpunkt des Schreibens final LIFECYCLE_VERSION = "2.3.0-alpha05"

AKTUALISIEREN:

Außerdem können wir die Fortschrittsaktualisierung mit implementieren onProgressUpdate Funktion:

fun <P, R> CoroutineScope.executeAsyncTask(
        onPreExecute: () -> Unit,
        doInBackground: suspend (suspend (P) -> Unit) -> R,
        onPostExecute: (R) -> Unit,
        onProgressUpdate: (P) -> Unit
) = launch {
    onPreExecute()

    val result = withContext(Dispatchers.IO) {
        doInBackground {
            withContext(Dispatchers.Main) { onProgressUpdate(it) }
        }
    }
    onPostExecute(result)
}

Beliebig verwenden CoroutineScope (siehe Implementierungen oben) können wir es nennen:

someScope.executeAsyncTask(
    onPreExecute = {
        // ... runs in Main Thread
    }, doInBackground = { publishProgress: suspend (progress: Int) -> Unit ->
        
        // ... runs in Background Thread

        // simulate progress update
        publishProgress(50) // call `publishProgress` to update progress, `onProgressUpdate` will be called
        delay(1000)
        publishProgress(100)

        
        "Result" // send data to "onPostExecute"
    }, onPostExecute = {
        // runs in Main Thread
        // ... here "it" is a data returned from "doInBackground"
    }, onProgressUpdate = {
        // runs in Main Thread
        // ... here "it" contains progress
    }
)

1646102831 124 Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
Mailand Pithadia

Verwenden Sie diese Klasse, um eine Hintergrundaufgabe im Hintergrundthread dieser Klasse auszuführen Funktioniert für alle Android-API-Versionen, einschließlich Android 11 Auch dieser Code ist die gleiche Arbeit wie AsyncTask mit doInBackground und onPostExecute Methoden

public abstract class BackgroundTask {

    private Activity activity;
    public BackgroundTask(Activity activity) {
        this.activity = activity;
    }

    private void startBackground() {
        new Thread(new Runnable() {
            public void run() {

                doInBackground();
                activity.runOnUiThread(new Runnable() {
                    public void run() {

                        onPostExecute();
                    }
                });
            }
        }).start();
    }
    public void execute(){
        startBackground();
    }

    public abstract void doInBackground();
    public abstract void onPostExecute();

}

Nachdem Sie die obige Klasse kopiert haben, können Sie sie dann damit verwenden:

new BackgroundTask(MainActivity.this) {
        @Override
        public void doInBackground() {

            //put you background code
            //same like doingBackground
            //Background Thread
        }

        @Override
        public void onPostExecute() {

            //hear is result part same
            //same like post execute
            //UI Thread(update your UI widget)
        }
    }.execute();

Die AsyncTask API ist in Android 11 veraltet Welche Alternativen gibt
kshitij86

Hier habe ich eine Alternative für AsyncTask mit Coroutinen erstellt, die genauso wie AsyncTask verwendet werden kann, ohne viel Codebasis in Ihrem Projekt zu ändern.

  1. Erstellen Sie eine neue abstrakte Klasse AsyncTaskCoroutine, die Eingabeparameter- und Ausgabeparameter-Datentypen verwendet. Diese Parameter sind natürlich optional 🙂

     import kotlinx.coroutines.Dispatchers
     import kotlinx.coroutines.GlobalScope
     import kotlinx.coroutines.async
     import kotlinx.coroutines.launch
    
     abstract class AsyncTaskCoroutine<I, O> {
         var result: O? = null
         //private var result: O
         open fun onPreExecute() {}
    
         open fun onPostExecute(result: O?) {}
         abstract fun doInBackground(vararg params: I): O
    
         fun <T> execute(vararg input: I) {
             GlobalScope.launch(Dispatchers.Main) {
                 onPreExecute()
                 callAsync(*input)
             }
         }
    
         private suspend fun callAsync(vararg input: I) {
             GlobalScope.async(Dispatchers.IO) {
                 result = doInBackground(*input)
             }.await()
             GlobalScope.launch(Dispatchers.Main) {
    
                 onPostExecute(result)
    
    
             }
         }
     }
    

2 . Innerhalb der Aktivität verwenden Sie dies jetzt genauso wie Ihre alte AsycnTask

 new AsyncTaskCoroutine() {
                @Override
                public Object doInBackground(Object[] params) {
                    return null;
                }
    
                @Override
                public void onPostExecute(@Nullable Object result) {
    
                }
    
                @Override
                public void onPreExecute() {
    
                }
            }.execute();
  1. Falls Sie Pass-Parameter senden müssen

      new AsyncTaskCoroutine<Integer, Boolean>() {
    
         @Override
         public Boolean doInBackground(Integer... params) {
             return null;
         }
    
         @Override
         public void onPostExecute(@Nullable Boolean result) {
    
         }
    
         @Override
         public void onPreExecute() {
    
         }
     }.execute();
    

Android veraltet AsyncTask API in Android 11, um zunächst einen Teil der Probleme zu beseitigen.

Also, was ist jetzt?

  • Fäden
  • Vollstrecker
  • RxJava
  • Hörbare Zukunft
  • Coroutinen 🔥

Warum Coroutinen?

Coroutinen sind die Kotlin-Methode zur asynchronen Programmierung. Die Compiler-Unterstützung ist seit Kotlin 1.3 stabil, zusammen mit a
kotlinx.coroutines Bücherei –

  • Strukturierte Parallelität
  • Nicht blockierender, sequentieller Code
  • Stornierungsausbreitung
  • Natürliche Ausnahmebehandlung

  • Ich habe gehört, dass Coroutines einen “einfachen Einstieg” haben. Bedeutet das, dass es leicht zu durchbrechen ist?

    – Branddd

    11. November 2020 um 10:50 Uhr

895640cookie-checkDie AsyncTask-API ist in Android 11 veraltet. Welche Alternativen gibt es?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy