Die AsyncTask-API ist in Android 11 veraltet. Welche Alternativen gibt es?
Lesezeit: 11 Minuten
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.
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;
}
}
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
Kaschfa Khan
Sie können direkt verwenden Executors von java.util.concurrent Paket.
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
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?
Mit letzterem kann es ziemlich einfach erreicht werden:
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
}
Verwenden Sie die Funktion mit jedem CoroutineScope:
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
}
)
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();
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.
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();
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
8956400cookie-checkDie AsyncTask-API ist in Android 11 veraltet. Welche Alternativen gibt es?yes
“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 migriertAsyncTask
. 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 alsAsyncTask
(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