javaandroidkotlinandroid-asynctaskkotlin-coroutines

The AsyncTask API is deprecated in Android 11. What are the alternatives?


Google is deprecating Android AsyncTask API in Android 11 and suggesting to use java.util.concurrent instead. you can check out the commit here

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

If you’re maintaining an older codebase with asynchronous tasks in Android, you’re likely going to have to change it in future. My question is that what should be proper replacement of the code snippet shown below using java.util.concurrent. It is a static inner class of an Activity. I am looking for something that will work with 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) ;
        }     


    }

Solution

  • private WeakReference<MyActivity> activityReference;
    

    Good riddance that it's deprecated, because the WeakReference<Context> was always a hack, and not a proper solution.

    Now people will have the opportunity to sanitize their code.


    AsyncTask<String, Void, MyPojo> 
    

    Based on this code, Progress is actually not needed, and there is a String input + MyPojo output.

    This is actually quite easy to accomplish without any use of 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);
                });
            });
        }
    }
    

    How to pass in the String? Like 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;
        }
    }
    

    And

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

    This example used a single-threaded pool which is good for DB writes (or serialized network requests), but if you want something for DB reads or multiple requests, you can consider the following Executor configuration:

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