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

21

EDIT : Diese Frage ist kein Duplikat als

  1. Vor ein paar Tagen wurde ein AOSP-Commit für die Abschreibung durchgeführt.
  2. Die andere Frage betrifft die Verwendung von AsyncTaskLoader über AsyncTask.


Google lehnt die Android AsyncTask-API in Android 11 ab und schlägt vor, sie java.util.concurrentstattdessen zu verwenden . Sie können das Commit hier überprüfen

 *
 * @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 verwalten, müssen Sie diese wahrscheinlich in Zukunft ändern. Meine Frage ist, was der richtige Ersatz für das unten gezeigte Code-Snippet sein soll java.util.concurrent. Es ist eine statische innere Klasse einer Aktivität. Ich suche etwas, mit dem ich arbeiten kannminSdkVersion 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) ;
        }     


    }
Zeeshan
quelle
5
"Veraltet" bedeutet, dass Google empfiehlt, dass Sie zu etwas anderem wechseln. Dies bedeutet nicht, dass die Klasse bald entfernt wird. Insbesondere AsyncTaskkann nicht entfernt werden, ohne die Abwärtskompatibilität zu beeinträchtigen.
CommonsWare
2
@ Style-7 ist es nicht.
EpicPandaForce
Es gibt keine "statische innere Klasse". Du meinst eine statisch verschachtelte Klasse.
Beroal

Antworten:

22
private WeakReference<MyActivity> activityReference;

Gute Befreiung, dass es veraltet ist, denn das 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 Progresswird eigentlich nicht benötigt, und es gibt eine StringEingabe + MyPojoAusgabe.

Dies ist ohne Verwendung von AsyncTask recht einfach zu erreichen.

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? Wie 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-Threaded-Pool verwendet, der für DB-Schreibvorgänge (oder serialisierte Netzwerkanforderungen) geeignet ist. Wenn Sie jedoch etwas für DB-Lesevorgänge oder mehrere Anforderungen wünschen, 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>());
EpicPandaForce
quelle
Ich erhalte eine Fehlermeldung executor.post. Methode kann nicht aufgelöst werden
Kris B
@KrisB anscheinend heißt es execute()stattpost()
EpicPandaForce
Wissen Sie, ob es in Ordnung ist, ein Contextin dieses zu übergeben? Ich weiß, dass das Übergeben eines Contextin AsyncTaskeines seiner Probleme war.
Kris B
Sie müssen dies weiterhin in einem ViewModel, einem beibehaltenen Fragment, einem Singleton oder was auch immer ausführen, wie Sie es normalerweise mit asynchronem Android tun würden.
EpicPandaForce
1
newSingleThreadExecutorist besser für Schreibvorgänge, aber Sie sollten auf jeden Fall das THREAD_POOL_EXECUTORam Ende des Beitrags für Datenbanklesevorgänge verwenden.
EpicPandaForce
3

Google empfiehlt die Verwendung des Concurrency-Frameworks von Java oder von Kotlin Coroutines. Aber Rxjava hat am Ende viel mehr Flexibilität und Funktionen als Java-Parallelität und hat so einiges an Popularität gewonnen.

Wahab Khan Jadon
quelle