Android AsyncTask API en desuso en Android 11. ¿Cuáles son las alternativas?

21

EDITAR : Esta pregunta no es un duplicado como

  1. Hace solo un par de días se realizó el compromiso de AOSP con respecto a la degradación.
  2. La otra pregunta es sobre el uso de AsyncTaskLoader sobre AsyncTask.


Google está desaprobando la API de Android AsyncTask en Android 11 y sugiere usar java.util.concurrenten su lugar. puedes ver el commit aquí

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

Si mantiene una base de código más antigua con tareas asincrónicas en Android, es probable que tenga que cambiarla en el futuro. Mi pregunta es cuál debería ser el reemplazo adecuado del fragmento de código que se muestra a continuación utilizando java.util.concurrent. Es una clase interna estática de una Actividad. Estoy buscando algo que funcioneminSdkVersion 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
fuente
55
"Desaprobado" significa que Google recomienda que te mudes a otra cosa. No significa que la clase se eliminará en el corto plazo. En particular, AsyncTaskno se puede eliminar sin romper la compatibilidad con versiones anteriores.
CommonsWare
2
@ Style-7 no lo es.
EpicPandaForce
No existe tal cosa como una "clase interna estática". Te refieres a una clase anidada estática.
Beroal

Respuestas:

23
private WeakReference<MyActivity> activityReference;

Buena idea de que está en desuso, porque WeakReference<Context>siempre fue un truco, y no una solución adecuada .

Ahora las personas tendrán la oportunidad de desinfectar su código.


AsyncTask<String, Void, MyPojo> 

Basado en este código, en Progressrealidad no es necesario, y hay una Stringentrada + MyPojosalida.

En realidad, esto es bastante fácil de lograr sin el uso de 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);
            });
        });
    }
}

¿Cómo pasar la cuerda? Al igual que:

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

Y

// 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 ejemplo utilizó un grupo de subprocesos único que es bueno para las escrituras de DB (o solicitudes de red serializadas), pero si desea algo para lecturas de DB o solicitudes múltiples, puede considerar la siguiente configuración de Ejecutor:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
EpicPandaForce
fuente
Me aparece un error executor.post. No se puede resolver el método
Kris B
@KrisB aparentemente se llama en execute()lugar depost()
EpicPandaForce
¿Sabes si está bien pasar un Contextesto? Sé que pasar un Contextinto AsyncTaskfue uno de sus problemas.
Kris B
Todavía necesita ejecutar esto en un ViewModel, fragmento retenido, singleton o cualquier otra cosa, como lo haría normalmente con cualquier cosa asíncrona en Android.
EpicPandaForce
1
newSingleThreadExecutores mejor para las escrituras, pero definitivamente debe usar THREAD_POOL_EXECUTORal final de la publicación para las lecturas de la base de datos.
EpicPandaForce
3

Google recomienda utilizar el marco de simultaneidad de Java o Kotlin Coroutines. pero Rxjava termina teniendo mucha más flexibilidad y características que la concurrencia de Java, por lo que ganó bastante popularidad.

Wahab Khan Jadon
fuente