API do Android AsyncTask descontinuada no Android 11.Quais são as alternativas?

21

EDIT : Esta pergunta não é uma duplicata como

  1. Apenas alguns dias atrás, o comprometimento do AOSP com a depreciação foi feito.
  2. A outra pergunta é sobre o uso do AsyncTaskLoader sobre o AsyncTask.


O Google está preterindo a API do AsyncTask do Android no Android 11 e sugerindo o uso java.util.concurrent. você pode conferir o commit aqui

 *
 * @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 você estiver mantendo uma base de código mais antiga com tarefas assíncronas no Android, provavelmente precisará alterá-la no futuro. Minha pergunta é: o que deve ser a substituição adequada do snippet de código mostrado abaixo usando java.util.concurrent. É uma classe interna estática de uma atividade. Estou à procura de algo que funcione comminSdkVersion 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
fonte
5
"Descontinuado" significa que o Google está recomendando que você mude para outra coisa. Isso não significa que a turma será removida em breve. Em particular, AsyncTasknão pode ser removido sem quebrar a compatibilidade com versões anteriores.
CommonsWare
2
@ Style-7 não é.
EpicPandaForce
Não existe uma "classe interna estática". Você quer dizer uma classe aninhada estática.
beroal 5/03

Respostas:

22
private WeakReference<MyActivity> activityReference;

Boa indicação de que está obsoleta, porque oWeakReference<Context> sempre foi um hack e não uma solução adequada .

Agora as pessoas terão a oportunidade de higienizar seu código.


AsyncTask<String, Void, MyPojo> 

Com base nesse código, Progressna verdade não é necessário e existe umaString entrada + MyPojosaída.

Isso é realmente muito fácil de realizar sem qualquer uso do 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);
            });
        });
    }
}

Como passar na String? Igual a:

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

Este exemplo usou um pool de thread único que é bom para gravações de banco de dados (ou solicitações de rede serializadas), mas se você deseja algo para leituras de banco de dados ou várias solicitações, considere a seguinte configuração de Executor:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
EpicPandaForce
fonte
Estou recebendo um erro executor.post. Não é possível resolver método
Kris B
@KrisB aparentemente ele é chamado execute()em vez depost()
EpicPandaForce
Você sabe se não há problema em passar por Contextisso? Eu sei que passar Contextpara AsyncTaskum era um dos seus problemas.
Kris B
Você ainda precisa executar isso em um ViewModel, fragmento retido, singleton ou qualquer outra coisa, como faria normalmente com qualquer coisa assíncrona no Android.
EpicPandaForce 9/11/19
11
newSingleThreadExecutoré melhor para gravações, mas você definitivamente deve usar o THREAD_POOL_EXECUTORno final da postagem para leituras do banco de dados.
EpicPandaForce 11/11/19
3

O Google recomenda o uso da estrutura de concorrência em Java ou da Kotlin Coroutines. mas o Rxjava acaba tendo muito mais flexibilidade e recursos do que a concorrência java, então ganhou bastante popularidade.

Wahab Khan Jadon
fonte