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

We Are Going To Discuss About The AsyncTask API is deprecated in Android 11. What are the alternatives?. So lets Start this Java Article.

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

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

    You can directly use Executors from java.util.concurrent package.
    I also searched about it and I found a solution in this Android Async API is Deprecated post.
    Unfortunately, the post is using Kotlin, but after a little effort I have converted it into Java. So here is the solution.

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

    You can directly use Executors from java.util.concurrent package.
    I also searched about it and I found a solution in this Android Async API is Deprecated post.
    Unfortunately, the post is using Kotlin, but after a little effort I have converted it into Java. So here is the solution.

Solution 1

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

Original Author Of This Content

Solution 2

You can directly use Executors from java.util.concurrent package.

I also searched about it and I found a solution in this Android Async API is Deprecated post.

Unfortunately, the post is using Kotlin, but after a little effort I have converted it into Java. So here is the solution.

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(new Runnable() {
    @Override
    public void run() {

        //Background work here

        handler.post(new Runnable() {
            @Override
            public void run() {
                //UI Thread work here
            }
        });
    }
});

Pretty simple right? You can simplify it little more if you are using Java 8 in your project.

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(() -> {
    //Background work here
    handler.post(() -> {
        //UI Thread work here
    });
});

Still, it cannot defeat kotlin terms of conciseness of the code, but better than the previous java version.

Hope this will help you. Thank You

Original Author Of This Content

Solution 3

One of the simplest alternative is to use Thread

new Thread(new Runnable() {
    @Override
    public void run() {
        // do your stuff
        runOnUiThread(new Runnable() {
            public void run() {
                // do onPostExecute stuff
            }
        });
    }
}).start();

If your project supports JAVA 8, you can use lambda:

new Thread(() -> {
    // do background stuff here
    runOnUiThread(()->{
        // OnPostExecute stuff here
    });
}).start();

Original Author Of This Content

Solution 4

According to the Android documentation AsyncTask was deprecated in API level 30 and it is suggested to use the standard java.util.concurrent or Kotlin concurrency utilities instead.

Using the latter it can be achieved pretty simple:

  1. Create generic extension function on CoroutineScope:

     fun <R> CoroutineScope.executeAsyncTask(
             onPreExecute: () -> Unit,
             doInBackground: () -> R,
             onPostExecute: (R) -> Unit
     ) = launch {
         onPreExecute() // runs in Main Thread
         val result = withContext(Dispatchers.IO) { 
             doInBackground() // runs in background thread without blocking the Main Thread
         }
         onPostExecute(result) // runs in Main Thread
     } 
    
  2. Use the function with any CoroutineScope:

    • In ViewModel:

      class MyViewModel : ViewModel() {
      
          fun someFun() {
              viewModelScope.executeAsyncTask(onPreExecute = {
                  // ... runs in Main Thread
              }, doInBackground = {
                  // ... runs in Worker(Background) Thread
                  "Result" // send data to "onPostExecute"
              }, onPostExecute = {
                  // runs in Main Thread
                  // ... here "it" is the data returned from "doInBackground"
              })
          }
      }
      
    • In Activity or Fragment:

      lifecycleScope.executeAsyncTask(onPreExecute = {
          // ... runs in Main Thread
      }, doInBackground = {
          // ... runs in Worker(Background) Thread
          "Result" // send data to "onPostExecute"
      }, onPostExecute = {
          // runs in Main Thread
          // ... here "it" is the data returned from "doInBackground"
      })
      

    To use viewModelScope or lifecycleScope add next line(s) to dependencies of the app’s build.gradle file:

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
    

    At the time of writing final LIFECYCLE_VERSION = "2.3.0-alpha05"

UPDATE:

Also we can implement progress updating using onProgressUpdate function:

fun <P, R> CoroutineScope.executeAsyncTask(
        onPreExecute: () -> Unit,
        doInBackground: suspend (suspend (P) -> Unit) -> R,
        onPostExecute: (R) -> Unit,
        onProgressUpdate: (P) -> Unit
) = launch {
    onPreExecute()

    val result = withContext(Dispatchers.IO) {
        doInBackground {
            withContext(Dispatchers.Main) { onProgressUpdate(it) }
        }
    }
    onPostExecute(result)
}

Using any CoroutineScope (see implementations above) we can call it:

someScope.executeAsyncTask(
    onPreExecute = {
        // ... runs in Main Thread
    }, doInBackground = { publishProgress: suspend (progress: Int) -> Unit ->
        
        // ... runs in Background Thread

        // simulate progress update
        publishProgress(50) // call `publishProgress` to update progress, `onProgressUpdate` will be called
        delay(1000)
        publishProgress(100)

        
        "Result" // send data to "onPostExecute"
    }, onPostExecute = {
        // runs in Main Thread
        // ... here "it" is a data returned from "doInBackground"
    }, onProgressUpdate = {
        // runs in Main Thread
        // ... here "it" contains progress
    }
)

Original Author Of This Content

Conclusion

So This is all About This Tutorial. Hope This Tutorial Helped You. Thank You.

Also Read,

Siddharth

I am an Information Technology Engineer. I have Completed my MCA And I have 4 Year Plus Experience, I am a web developer with knowledge of multiple back-end platforms Like PHP, Node.js, Python and frontend JavaScript frameworks Like Angular, React, and Vue.

Leave a Comment