API Android AsyncTask che si deprecano in Android 11.Quali sono le alternative?


21

EDIT : questa domanda non è un duplicato di

  1. Solo un paio di giorni fa è stato eseguito il commit di AOSP sulla deprecazione.
  2. L'altra domanda riguarda l'uso di AsyncTaskLoader su AsyncTask.


Google sta deprecando l'API Android AsyncTask in Android 11 e sta suggerendo di utilizzare java.util.concurrentinvece. puoi dare un'occhiata al commit qui

 *
 * @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> {

Se stai mantenendo una base di codice precedente con attività asincrone in Android, probabilmente dovrai cambiarla in futuro. La mia domanda è che cosa dovrebbe essere la corretta sostituzione dello snippet di codice mostrato sotto usando java.util.concurrent. È una classe interna statica di un'attività. Sto cercando qualcosa con cui lavorareminSdkVersion 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) ;
        }     


    }

5
"Obsoleto" significa che Google ti consiglia di passare a qualcos'altro. Ciò non significa che la classe verrà rimossa presto. In particolare, AsyncTasknon può essere rimosso senza interrompere la compatibilità all'indietro.
CommonsWare


2
@ Style-7 non lo è.
EpicPandaForce

Non esiste una "classe interna statica". Intendi una classe nidificata statica.
Beroal

Risposte:


23
private WeakReference<MyActivity> activityReference;

Buon cavalcatura che è deprecato, perché WeakReference<Context>era sempre un trucco, e non una soluzione adeguata .

Ora le persone avranno l'opportunità di disinfettare il proprio codice.


AsyncTask<String, Void, MyPojo> 

Sulla base di questo codice, in Progressrealtà non è necessario e c'è un Stringinput + MyPojooutput.

Questo è in realtà abbastanza facile da realizzare senza l'uso di AsyncTask.

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);
            });
        });
    }
}

Come passare la stringa? Così:

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;
    }
}

E

// 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 questo esempio è stato utilizzato un pool a thread singolo che è utile per le scritture di DB (o richieste di rete serializzate), ma se si desidera qualcosa per le letture di DB o richieste multiple, è possibile prendere in considerazione la seguente configurazione di Executor:

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

Ricevo un errore executor.post. Impossibile risolvere il metodo
Kris B

@KrisB apparentemente si chiama execute()invece dipost()
EpicPandaForce

Sai se è ok passare a Contextquesto? So che passare a Contextin AsyncTaskera uno dei suoi problemi.
Kris B,

Devi ancora eseguirlo in un ViewModel, frammento mantenuto, singleton o qualsiasi altra cosa, come faresti normalmente con qualsiasi cosa asincrona in Android.
EpicPandaForce

1
newSingleThreadExecutorè meglio per le scritture, ma dovresti assolutamente usare THREAD_POOL_EXECUTORla fine del post per le letture del database.
EpicPandaForce,

3

Google consiglia di utilizzare il framework di concorrenza Java o Coroutine di Kotlin. ma Rxjava finisce per avere molta più flessibilità e funzionalità rispetto alla concorrenza java, quindi ha guadagnato un po 'di popolarità.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.