224

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


    }
Edric
  • 24,639
  • 13
  • 81
  • 91
Zeeshan
  • 11,851
  • 21
  • 73
  • 98
  • 45
    "Deprecated" means that Google is recommending that you move to something else. It does not mean that the class will be removed any time soon. In particular, `AsyncTask` cannot be removed without breaking backwards compatibility. – CommonsWare Nov 08 '19 at 13:52
  • Possible duplicate of [Is AsyncTask deprecated now w/ AsyncTaskLoader?](https://stackoverflow.com/questions/43990084/is-asynctask-deprecated-now-w-asynctaskloader) – Style-7 Nov 08 '19 at 14:21
  • 11
    @Style-7 it is not. – EpicPandaForce Nov 08 '19 at 14:55
  • There is no such thing as a "static inner class". You mean a static nested class. – beroal Mar 05 '20 at 17:56
  • 27
    This is a disaster. It's recommended to use `AsyncTask` from official Android Document. I was a backend developer, already familiar with the executorService. For this recommendation, I migrated all background tasks to use `AsyncTask`. And now they tell us not to use it? – Kimi Chiu May 09 '21 at 06:35
  • 1
    @CommonsWare starting with Android 11 Google started deleting deprecated methods. – Duna Aug 12 '21 at 16:18
  • 1
    @Duna: Got any examples? They delete deprecated methods from libraries, as developers control the versions of libraries that they use. But, as I noted, `AsyncTask` cannot be removed without breaking backwards compatibility. – CommonsWare Aug 12 '21 at 18:41
  • @CommonsWare yes it is working fine in android 11 and i'm going to use till it is working or i should move to alternative asap? – Addy Nov 24 '21 at 07:03
  • 3
    @Addy: The specific concern that I commented on here is `AsyncTask` being *deleted*, and that cannot happen without breaking lots of existing apps. Programmers should learn other techniques than `AsyncTask` (RxJava, Kotlin coroutines, etc.) simply because they are better and at this point are used more widely in professional settings. – CommonsWare Nov 24 '21 at 12:05
  • @EpicPandaForce https://developer.android.com/reference/android/os/AsyncTask it is – metvsk Dec 14 '21 at 13:11
  • Maybe this can help you https://medium.com/swlh/asynctask-is-deprecated-now-what-f30c31362761 – Yohannes Masterous Dec 31 '21 at 08:13
  • 1
    @KimiChiu; this is one of the many things why I hate developing in Android. Pages full of fancy stuff and arty-farty concepts, saying they have the solution for the worlds problem, ending up throwing it all in the bin because it's so bad after all. CreateThread in win32 is more than 30 years old, it has it's flaws, but it does the job if you know what you are doing. Also reading the MSDN-programming-reference doesn't take ages like with Android... – Jomme Mar 12 '23 at 15:47
  • @KimiChiu I learned a long time ago spending time on someone else's agenda is normally a waste of time. This is just like HTML certain HTML tags like center being deprecated - that doesn't really matter because all browsers still support it and probably won't stop. If they do, some day, I'll go through all of my code, if it even matters to me at that point in time. – Dan Chase Jun 27 '23 at 16:49

19 Answers19

184

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

Teocci
  • 7,189
  • 1
  • 50
  • 48
Kashfa Khan
  • 2,165
  • 1
  • 11
  • 8
  • 7
    Actually you can go one more step down: Executors.newSingleThreadExecutor().execute(() -> dao.insert(data)); – arun Aug 09 '21 at 00:23
  • 2
    Thank you for this! It helped me a lot when calling server API calls. But what if I want to show some updating progress bars? where can I put the onProgressUpdate part? – Kroi Nov 07 '21 at 13:38
  • @Kroi you'd have to call `handler.post` everytime you want to post an update to main thread – pavi2410 Mar 12 '22 at 09:03
  • How to stop the execution of tasks?, for example when closing the activity that has called it, etc. In my case I use it in a word search engine of my database, I want that when changing the text of an EditText it stops the current query and starts a new one, but I can't find a way to stop the ExecutorService. – JP711 Mar 22 '22 at 18:29
  • I try it, I can't understand when the background task is still executing and I'm receiving the post execute result immediately. Where is the catch – mikegrep Oct 08 '22 at 14:08
  • 1
    d= (◕‿↼ ) Nice short and clean answer, where "clean" means without the non-sense about "don't use `WeakReference` and go use `LiveData` instead". – Top-Master Jan 25 '23 at 16:30
  • `LiveData.observe(myActivity, ...)` method is even worse than a weak-ref, because the observer is IGNORED once life-cycle ends, **but** if we capture a weak-ref inside a normal observer, we at least can handle `null`, like changing configurations to retry later. See also [Static way to get `Context` in Android](https://stackoverflow.com/a/5114361/8740349) – Top-Master Jan 25 '23 at 16:32
  • 3
    I don't see what advantage this has over using AsyncTask correctly. Both your approach and AsyncTask use similar components from Java's concurerncy package and the code shown above does not do anything to prevent the "memory leaks" associated with improper use of AsyncTask when used from within the context of an Activity or Fragment. – user1608385 Apr 13 '23 at 20:50
  • what about progressUpdate? How to handle that? – Prajwal Waingankar Jun 20 '23 at 11:29
122
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>());
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • I am getting an error on `executor.post`. Cannot resolve method – Kris B Nov 09 '19 at 00:37
  • @KrisB apparently it's called `execute()` instead of `post()` – EpicPandaForce Nov 09 '19 at 11:14
  • Do you know if it's ok to pass a `Context` into this? I know that passing a `Context` into `AsyncTask` was one of it's issues. – Kris B Nov 09 '19 at 22:40
  • You still need to run this in a ViewModel, retained fragment, singleton, or whatever else, as you normally would with anything async in Android. – EpicPandaForce Nov 09 '19 at 23:28
  • For progress update support, you can check this Kotlin example: https://www.reddit.com/r/androiddev/comments/dt2kbh/google_is_deprecating_androids_asynctask_api_in/f747k2e/ – EpicPandaForce Nov 10 '19 at 15:21
  • Thanks, I replaced all my `AsyncTasks` with your code. Do you know if I should be using `newSingleThreadExecutor` for all async operations or is one better for database reads vs. writers? – Kris B Nov 10 '19 at 15:49
  • 1
    `newSingleThreadExecutor` is better for writes, but you should definitely use the `THREAD_POOL_EXECUTOR` at the end of the post for database reads. – EpicPandaForce Nov 11 '19 at 01:08
  • The `WeakReference` hack isn't inherently tied to AsyncTask, though, is it? The Runnable someone passes to your `TaskRunner.executeAsync()` is likely to capture an Activity/Fragment reference and leak it if not dealt with. Someone might try the same WeakReference hack to get around that instead of properly supporting cancellation. In the same way `AsyncTask` could be used in a more proper way, supporting cancellation and being actively cancelled by the user in `onDestroy()`. Though I'm not complaining about them deprecating such a clumsy tool. – Tenfour04 Feb 20 '20 at 17:23
  • That's why the sample I provided runs it in the ViewModel instead although yes, what I wrote doesn't cancel the task. You could handle it with interruptions if needed, but it's almost easier to run the async task in a singleton global context and use event emission (just like how ViewModel communicates one-off events to its view) – EpicPandaForce Feb 20 '20 at 18:24
  • 2
    In TaskRunner I get a compiler error "Unhandled Exception java.lang.Exception` at `callable.call()` ... what's the best way to handle this? – k2col Apr 29 '20 at 08:30
  • Is there a built-in equivalent to `TaskRunner` in Android or AndroidX? It looks like a neat way to do it but seems strange that something so important isn't built-in. – Sam May 09 '20 at 02:08
  • @Sam the built-in version was called AsyncTask and it was so bad it got deprecated :p – EpicPandaForce May 09 '20 at 10:02
  • How to know if my task is finished or not? – Jones Jun 16 '20 at 11:37
  • You get a callback when it's done. If you didn't get a callback, then it's not yet done. – EpicPandaForce Jun 16 '20 at 12:18
  • 2
    I really appreciated this example. Thanks! I ended up using this almost exactly as is. I used a `static` executor like you showed in your code sample at the very end but still used `Executors.newSingleThreadExecutor()`. – dontangg Jun 24 '20 at 22:56
  • How can I cancel an Task which is Executed this way (and interrupt it)? – Jones Jun 25 '20 at 10:18
  • 2
    If you do need cancelation, then instead of executor.execute, you have to use executor.submit and cancel the future. https://www.baeldung.com/java-future – EpicPandaForce Jun 25 '20 at 10:40
  • Oh god, so it turns out Handler is now deprecated also..... – Paula Livingstone Aug 18 '20 at 11:53
  • That can't be right. `android.os.Handler` is essential for communicating to the UI thread or any other HandlerThreads. Only the no-arg constructor seems to be deprecated, `Handler(Looper.getMainLooper())` seems to be legit. – EpicPandaForce Aug 18 '20 at 13:30
  • 1
    I feel like this solution is a simple version of the AsyncTask, because AsyncTask uses Executor and Handler under the hood and provides other features such as cancel, update progress, etc. – Son Truong Nov 21 '20 at 05:40
  • So why are we deprecating AsyncTask only to re-create it from scratch, and still follow apparently bad habits with memory leaks? If I need to hold a reference to an Activity for use after my async task completes (using whatever async mechanism) then surely I am *still* going to need a WeakReference to the Activity, just as before? I don't see what is gained by using something that is not AsyncTask but basically is... – drmrbrewer Nov 26 '20 at 23:19
  • You've never once needed a WeakReference, you needed non-config instance scope (retained fragment scope, now ViewModel scope) and observer pattern for pending values. You only need weak ref if you're building a reactive data layer, and even then only if you're not building on top of lifecycle awareness or structured concurrency. – EpicPandaForce Nov 27 '20 at 01:44
  • 1
    But the use of `WeakReference` isn't connected specifically to the use of `AsyncTask`, so your opening statement "Good riddance that it [AsyncTask] is deprecated, because the WeakReference was always a hack, and not a proper solution" isn't really relevant? Anyway, I've now used your `TaskRunner` to eliminate `AsyncTask` entirely from my code, and maybe it does seem a bit cleaner overall, which is good, but nothing has fundamentally changed... in particular I still use `WeakReference` just as I did before, rather proving the point. Maybe that is a task for the next cleanup. Thanks! – drmrbrewer Nov 30 '20 at 15:59
  • How do I publish progress ? – Prashant Jan 17 '21 at 17:40
  • @prashant https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives/58767934?noredirect=1#comment103861875_58767934 – EpicPandaForce Jan 17 '21 at 20:49
  • I tried this and the app just drops out (with no errors in logcat) as soon as execute() is called. Tried both types of Executor. Mind you, I'm calling from an Activity rather than from a ViewModel. Is this the reason? – quilkin Feb 17 '21 at 17:14
  • I'd have to see the code and the exception stack trace to tell you – EpicPandaForce Feb 17 '21 at 19:34
  • There are some cases when you really need a `WeakReference`, an example would be when working with a local library that accept a View parameter to do some fetching from network and update it. Since it is not part of your app module directly there is no way you can apply its changes without moving those classes to your app module itself. I would rather say that as much as possible avoid using `WeakReference` as it means you have a bad structure but no total restriction is imposed. After all they still exist until today and I see no Android documentation against using it. – Undefined function Apr 26 '21 at 13:25
  • @EpicPandaForce in that `LongRunningTask`, how do you get the reference to a context? – Sourav Kannantha B Sep 14 '21 at 06:10
  • @EpicPandaForce can you please review [this](https://codereview.stackexchange.com/q/267985/241242). – Sourav Kannantha B Sep 14 '21 at 09:02
  • I have one class which have `AsyncTask` like this - `new AsyncTask() {...}` means directly, it's not like i'm calling it from somewhere, so what about `params` from `doInBackground`??, for more info look at this - https://github.com/sharish/ScratchView/blob/master/views/src/main/java/com/cooltechworks/views/ScratchTextView.java#L317 – Vivek Thummar Oct 06 '21 at 07:14
  • @VivekThummar see `LongRunningTask ` in the answer – EpicPandaForce Oct 06 '21 at 08:19
  • Is there a version of this with an in-built timeout feature? – drmrbrewer Apr 17 '22 at 08:16
  • `LiveData.observe(myActivity, ...)` method is even worse than a weak-ref, because the observer is IGNORED once life-cycle ends, **but instead** if we capture a weak-ref inside a normal observer, we at least can handle `null`, like by changing configurations to retry later. **See also [Static way to get Context in Android](https://stackoverflow.com/a/5114361/8740349)** – Top-Master Jan 26 '23 at 19:11
  • @Top-Master you store a `MutableLiveData` in a `ViewModel` and therefore it makes sense for the observer to be ignored, as that's just to get the result to an activity. You handle the logic in either the ViewModel, or if you are handling onCleared and this shouldn't be cancellable then you run the operation in a singleton. WeakReferences for Activity/Fragment are effectively never needed. – EpicPandaForce Jan 26 '23 at 21:45
  • @EpicPandaForce I talk about the answer's [WeakReference is hack](https://proandroiddev.com/a-quick-story-about-async-callbacks-memory-leaks-weakreferences-and-misconceptions-78003b3d6b26) linked-post --- where first it complains that weak-ref gets `null`, while we may need to do something important, but then suggests as solution `observer` never being called ;-) – Top-Master Jan 26 '23 at 22:12
  • You say "Progress" is no longer needed, and that may be true for long running operations for which we only want to be notified upon completion, but don't you think it would be useful to show the progress of a long running task such as a data download and if so, how would you incorporate progress reporting into this scheme? – user1608385 Apr 13 '23 at 20:56
  • 1
    @user1608385 i did write it here https://www.reddit.com/r/androiddev/comments/dt2kbh/google_is_deprecating_androids_asynctask_api_in/f747k2e/ – EpicPandaForce Apr 14 '23 at 01:30
58

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();
Teocci
  • 7,189
  • 1
  • 50
  • 48
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
  • 2
    How to show percentage when background stuff called? – Ahamadullah Saikat Oct 03 '20 at 12:16
  • You need to use runOnUiThread to update your progress-bar or any other mechanism you are using for updating / displaying % of task completed. – Mayank Kumar Chaudhari Oct 03 '20 at 13:17
  • 24
    This solution has several drawbacks. First, the thread keeps a reference to the activity, this might leak the context and crash the app. Second, we cannot use this from a fragment. Third, we cannot update progress of the background task, Fourth, there is no way to cancel the thread. Finally, it creates many boilerplate code in the app. – Son Truong Nov 21 '20 at 05:53
  • Your code does not even compile....I think has some typos in, for example when you say `new Runnable({...})` you mean `new Runnable(){...}`. Because the first one is like you call a constructor and pass an array initializer, triggering a compiler error. the second one is the proper way to create anonymous inner classes – Adam Burley Jan 29 '21 at 00:37
  • @Son Truong I have solutions for three of your four problems. First, WeakReference can be used to prevent leak. Second, you can absolutely use this inside fragments via getActivity(). Fourth, you can cancel at any time using Executer and Future. – Faisal Khan Mar 02 '21 at 15:25
  • 3
    @SonTruong I have a few genuine questions to those drawbacks. 1: How/Why does the thread keep a reference of the activity, if its not specifically passed? I understand `runOnUiThread`, but for short tasks, this shouldn't be a problem, no? 3: Can't the progress of the background task simply be handled by a respective call within `runOnUiThread`, just like `publishProgress`/`onProgressionUpdate`? 4: Going Down `AsyncTask` and `FutureTask` code, all it does is use the `Thread.interrupt` functionality to create the `cancel` functionality. Wouldnt it be possible to do the same with this approach? – Benjamin Basmaci Aug 11 '21 at 14:12
43

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 which has Dispatchers.Main context:

    • 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 (viewModelScope/lifecycleScope, see implementations above) with Dispatchers.Main context 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
    }
)
Sergio
  • 27,326
  • 8
  • 128
  • 149
  • Do you have any suggestions on how to implement the `onProgressUpdate` as well using the kotlin coroutines? – Peter Jul 11 '20 at 05:55
  • 4
    have this solution available in java? – Adnan haider Mar 13 '21 at 05:51
  • @Adnanhaider I am afraid it is not. – Sergio Mar 14 '21 at 06:20
  • @Undefinedfunction `executeAsyncTask` is an extension function on `CoroutineScope`, you can create your own `CoroutineScope` and call `executeAsyncTask` on it. – Sergio Apr 26 '21 at 08:45
  • I tried to update the UI in `onPostExecute` but what I get is error `ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.` which seems that its not running in UI thread – Undefined function Apr 26 '21 at 10:17
  • @Undefinedfunction please try to use `MainScope` (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html) to call `executeAsyncTask` method: `mainScope.executeAsyncTask ()` – Sergio Apr 26 '21 at 12:35
  • The solution is really good however I think this approach means that your async task will be always inside ViewModel, Activity, or Fragment not in just regular class for example that only implements an interface. – Undefined function Apr 26 '21 at 12:49
  • To call `executeAsyncTask` we need some `CoroutineScope` with `Dispatchers.Main` context to run appropriate methods(`onPreExecute()`...) on the Main Thread. You can create a `CoroutineScope` with `Dispatchers.Main` context in any class. – Sergio Apr 26 '21 at 15:15
  • 1
    This solution saves the day! Ton thanks brooo – Fahad-Android Apr 21 '22 at 16:18
17

Use this class to execute background task in Background Thread this class is work for all android API version include Android 11 also this code is same work like AsyncTask with doInBackground and onPostExecute methods

public abstract class BackgroundTask {

    private Activity activity;
    public BackgroundTask(Activity activity) {
        this.activity = activity;
    }

    private void startBackground() {
        new Thread(new Runnable() {
            public void run() {

                doInBackground();
                activity.runOnUiThread(new Runnable() {
                    public void run() {

                        onPostExecute();
                    }
                });
            }
        }).start();
    }
    public void execute(){
        startBackground();
    }

    public abstract void doInBackground();
    public abstract void onPostExecute();

}

After copying the above class, you can then use it with this:

new BackgroundTask(MainActivity.this) {
        @Override
        public void doInBackground() {

            //put you background code
            //same like doingBackground
            //Background Thread
        }

        @Override
        public void onPostExecute() {

            //hear is result part same
            //same like post execute
            //UI Thread(update your UI widget)
        }
    }.execute();
Stidgeon
  • 2,673
  • 8
  • 20
  • 28
milan pithadia
  • 840
  • 11
  • 16
  • I am trying to implement this code in my app but the post execute code does not terminate. It continues running till i close the app. What can be done to eliminate this? – user3079559 Apr 01 '23 at 11:36
10

Android deprecated AsyncTask API in Android 11 to get rid of a share of problems to begin with.

So, what's now?

  • Threads
  • Executers
  • RxJava
  • Listenable Futures
  • Coroutines

Why Coroutines?

Coroutines are the Kotlin way to do asynchronous programming. Compiler support is stable since Kotlin 1.3, together with a kotlinx.coroutines library -

  • Structured Concurrency
  • Non-blocking, sequential code
  • Cancellation propagation
  • Natural Exception Handling
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
9

Here I created a Alternative for AsyncTask using Coroutines which can be used same as AsyncTask without changing much code base in your project.

  1. Create a new Abstract class AsyncTaskCoroutine which takes input parameter and output parameter datatypes of-course these parameters are optional :)

     import kotlinx.coroutines.Dispatchers
     import kotlinx.coroutines.GlobalScope
     import kotlinx.coroutines.async
     import kotlinx.coroutines.launch
    
     abstract class AsyncTaskCoroutine<I, O> {
         var result: O? = null
         //private var result: O
         open fun onPreExecute() {}
    
         open fun onPostExecute(result: O?) {}
         abstract fun doInBackground(vararg params: I): O
    
         fun <T> execute(vararg input: I) {
             GlobalScope.launch(Dispatchers.Main) {
                 onPreExecute()
                 callAsync(*input)
             }
         }
    
         private suspend fun callAsync(vararg input: I) {
             GlobalScope.async(Dispatchers.IO) {
                 result = doInBackground(*input)
             }.await()
             GlobalScope.launch(Dispatchers.Main) {
    
                 onPostExecute(result)
    
    
             }
         }
     }
    

2 . Inside Activity use this as same as your old AsycnTask now

 new AsyncTaskCoroutine() {
                @Override
                public Object doInBackground(Object[] params) {
                    return null;
                }
    
                @Override
                public void onPostExecute(@Nullable Object result) {
    
                }
    
                @Override
                public void onPreExecute() {
    
                }
            }.execute();
  1. InCase if you need to send pass params

      new AsyncTaskCoroutine<Integer, Boolean>() {
    
         @Override
         public Boolean doInBackground(Integer... params) {
             return null;
         }
    
         @Override
         public void onPostExecute(@Nullable Boolean result) {
    
         }
    
         @Override
         public void onPreExecute() {
    
         }
     }.execute();
    
kshitij86
  • 129
  • 1
  • 8
Kumar
  • 127
  • 1
  • 4
  • 11
    no kotlin please, first use Java, then maybe Kotlin as an alternative for those who are using it. Thanks – Darksymphony Oct 28 '20 at 19:32
  • 6
    @Darksymphony I completely disagree with you, question is old in terms of using Java. If you are still using Java for Android, you need to rethink your choice. He wrote a very good alternative for AsynTask. – Pankaj Kumar Dec 24 '20 at 03:31
  • 20
    hopefully Java will stay for next X years as the basic language for android. Someone lazy came with Kotlin and forced it to android devs with it's funny commands :) Maybe one day I will rethink. But as long as we have a choice, I'll stay with Java – Darksymphony Jan 02 '21 at 22:41
  • @Darksymphony Where is the problem to write some parts with Kotlin and some with JAVA? Should work without any real problems. – The incredible Jan Jan 11 '21 at 15:25
  • @TheincredibleJan yes you are right, but works not without including Kotlin dependencies – Darksymphony Jan 11 '21 at 15:50
  • Great this work really well with non context class but how will you cancel it or get a progress? – Undefined function Apr 26 '21 at 11:05
  • Great example but instead of GlobalScope I would recommend to use CoroutineContext – Duna Aug 13 '21 at 06:54
  • 1
    @Darksymphony Kotlin is the superior language, no question. You have to adapt to the times. – BeLambda Aug 23 '21 at 23:21
  • Koltin isn't necessary "superior" the reason it was hastily invented is because google doesn't outright own java. And google knows this may become a problem even if that problem is all in their heads. Android itself is a hastily invented thing before Apple was the only phone solution on the planet. – dcarl661 Sep 09 '22 at 20:28
  • @Darksymphony you can save this Kotlin code in separate class and work with it with Java, you don't even look into it after that. – Acuna Oct 31 '22 at 19:09
5

The accepted answer is good. But... I didn't see cancel() method implementation

So my implementation with possibility to cancel the running task (simulating cancellation) is below. Cancel is needed to not run postExecute() method in case of task interruption.

public abstract class AsyncTaskExecutor<Params> {
    public static final String TAG = "AsyncTaskRunner";

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

    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private boolean mIsInterrupted = false;

    protected void onPreExecute(){}
    protected abstract Void doInBackground(Params... params);
    protected void onPostExecute(){}
    protected void onCancelled() {}

    @SafeVarargs
    public final void executeAsync(Params... params) {
        THREAD_POOL_EXECUTOR.execute(() -> {
            try {
                checkInterrupted();
                mHandler.post(this::onPreExecute);

                checkInterrupted();
                doInBackground(params);

                checkInterrupted();
                mHandler.post(this::onPostExecute);
            } catch (InterruptedException ex) {
                mHandler.post(this::onCancelled);
            } catch (Exception ex) {
                Log.e(TAG, "executeAsync: " + ex.getMessage() + "\n" + Debug.getStackTrace(ex));
            }
        });
    }

    private void checkInterrupted() throws InterruptedException {
        if (isInterrupted()){
            throw new InterruptedException();
        }
    }

    public void cancel(boolean mayInterruptIfRunning){
        setInterrupted(mayInterruptIfRunning);
    }

    public boolean isInterrupted() {
        return mIsInterrupted;
    }

    public void setInterrupted(boolean interrupted) {
        mIsInterrupted = interrupted;
    }
}

Example of using this class:

public class MySearchTask extends AsyncTaskExecutor<String> {

    public MySearchTask(){
    }

    @Override
    protected Void doInBackground(String... params) {
        // Your long running task
        return null;
    }

    @Override
    protected void onPostExecute() {
        // update UI on task completed
    }

    @Override
    protected void onCancelled() {
        // update UI on task cancelled
    }
}

MySearchTask searchTask = new MySearchTask();
searchTask.executeAsync("Test");
Vitaly
  • 334
  • 4
  • 14
5

Here I also created an Alternative for AsyncTask using abstract class and it can be just copied as a class.

/app/src/main/java/../AsyncTasks.java

public abstract class AsyncTasks {
    private final ExecutorService executors;

    public AsyncTasks() {
        this.executors = Executors.newSingleThreadExecutor();
    }

    private void startBackground() {
        onPreExecute();
        executors.execute(new Runnable() {
            @Override
            public void run() {
                doInBackground();
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        onPostExecute();
                    }
                });
            }
        });
    }

    public void execute() {
        startBackground();
    }

    public void shutdown() {
        executors.shutdown();
    }

    public boolean isShutdown() {
        return executors.isShutdown();
    }

    public abstract void onPreExecute();

    public abstract void doInBackground();

    public abstract void onPostExecute();
}

Implementation/ use of the above class

new AsyncTasks() {
     @Override
            public void onPreExecute() { 
             // before execution
      }

     @Override
            public void doInBackground() {
              // background task here 
            }

     @Override
            public void onPostExecute() { 
             // Ui task here
            }
     }.execute();
Attaullah
  • 3,856
  • 3
  • 48
  • 63
  • why you still name your solution with async task , even you use ExecutorService . – Islam Alshnawey Aug 28 '21 at 10:10
  • 1
    Just for simplicity for the beginner – Attaullah Aug 28 '21 at 14:50
  • In the above code from user Attaullah, is it possible to assign a specific name to each background task that is created through that class? That would make it easier to analyse the background tasks in the profiler of Android studio. – Patrick Oct 12 '21 at 20:54
  • Yes, possible you can easily give it a name. – Attaullah Oct 13 '21 at 05:51
  • I've added "Thread.currentThread().setName(threadName);" just below "public void run()" and I'm passing threadName through the Execute-method. That's working perfect. – Patrick Oct 19 '21 at 20:42
  • Another question on your code: How do you call the Shutdown-method in your code? Do you call it through "private AsyncTasks mTask;" -> "mTask = new AsyncTasks();" -> "mTask.execute();" and right afterwards "mTask.shutdown();"? – Patrick Oct 19 '21 at 20:45
  • Yes first check if is running then try to shutdown. if (!isShutdown()) mTask.shutdown(); – Attaullah Oct 19 '21 at 23:06
  • I'm glad someone understands this stuff better than I do! This is the only solution I've found that works for my situation. My question is, since you use Executors, would it be possible (for someone too old to learn new tricks without a week's studying) to implement a thread pool? Or, is that what @Patrick solved with his thread-naming addition? Thanks... EDIT: Um, maybe I should have looked further, it looks like a thread-pool system has already been implemented by another person who understands this stuff better than I do. I'm beginning to think everyone does! LOL – Trasd Jun 30 '23 at 02:28
4

Google recommends using Java’s Concurrency framework or Kotlin Coroutines. but Rxjava end to have much more flexibility and features then java concurrency so gained quite a bit of popularity.

Wahab Khan Jadon
  • 875
  • 13
  • 21
4

My custom replacement: https://github.com/JohnyDaDeveloper/AndroidAsync

It only works when the app is running (more specifically the activity which scheduled the task), but it's capable of updating the UI after the background task was completed

EDIT: My AsyncTask no longer reqires Activiy to function.

  • Wow, nice, but isn't it an implementation which Google using in their AsyncTask? Sorry, I don't know how are they implements it. – Acuna Oct 31 '22 at 19:13
4

I actually wrote two Medium stories about it:

The first one is with Java and a workaround with Runnable, the second is a Kotlin and coroutines solution. Both are with code examples of course.

Idan Damri
  • 196
  • 10
3

You can use this custom class as an alternative of the AsyncTask<>, this is the same as AsyncTask so you not need to apply extra efforts for the same.

import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TaskRunner {

    private static final int CORE_THREADS = 3;
    private static final long KEEP_ALIVE_SECONDS = 60L;
    private static TaskRunner taskRunner = null;
    private Handler handler = new Handler(Looper.getMainLooper());
    private ThreadPoolExecutor executor;

    private TaskRunner() {
        executor = newThreadPoolExecutor();
    }

    public static TaskRunner getInstance() {
        if (taskRunner == null) {
            taskRunner = new TaskRunner();
        }
        return taskRunner;
    }

    public void shutdownService() {
        if (executor != null) {
            executor.shutdown();
        }
    }

    public void execute(Runnable command) {
        executor.execute(command);
    }

    public ExecutorService getExecutor() {
        return executor;
    }

    public <R> void executeCallable(@NonNull Callable<R> callable, @NonNull OnCompletedCallback<R> callback) {
        executor.execute(() -> {
            R result = null;
            try {
                result = callable.call();
            } catch (Exception e) {
                e.printStackTrace(); // log this exception
            } finally {
                final R finalResult = result;
                handler.post(() -> callback.onComplete(finalResult));
            }
        });
    }

    private ThreadPoolExecutor newThreadPoolExecutor() {
        return new ThreadPoolExecutor(
                CORE_THREADS,
                Integer.MAX_VALUE,
                KEEP_ALIVE_SECONDS,
                TimeUnit.SECONDS,
                new SynchronousQueue<>()
        );
    }

    public interface OnCompletedCallback<R> {
        void onComplete(@Nullable R result);
    }
}

How to use it? Please follow the below examples.

With lambda expressions

TaskRunner.getInstance().executeCallable(() -> 1, result -> {
});


TaskRunner.getInstance().execute(() -> {
});

Without lambda expressions

TaskRunner.getInstance().executeCallable(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        return 1;
    }
}, new TaskRunner.OnCompletedCallback<Integer>() {
    @Override
    public void onComplete(@Nullable Integer result) {

    }
});

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

    }
});

Note: Don't forget to shutdown executors service

TaskRunner.getInstance().shutdownService();
Kishan Donga
  • 2,851
  • 2
  • 23
  • 35
  • I changed my mind, this is by far the best, easiest implementation I've found. I do however have a couple questions: is it safe to call shutdown with threads still active (like a cancel)? If I forget to shut it down, does it shutdown after 60 seconds (your default) of inactivity? I'll study the code too and try to answer these questions on my own, but multithreading escapes me (hopefully not after I study the code). Thanks. – Trasd Jun 30 '23 at 20:39
  • No need to answer. Found what I needed. Thanks, again. – Trasd Jun 30 '23 at 21:13
3

Just replace the whole class with this Thread and put it in a method to pass variables

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

and in Fragment add the Context to the runOnUiThread() methode:

 new Thread(() -> {
            // do background stuff here
            context.runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        }).start();
Mohamed Ben Romdhane
  • 1,005
  • 3
  • 11
  • 22
3

AsyncTask class does not seem to be removed any time soon, but we did simply un-deprecate it anyway, because:

  • We didn't want to add lots of suppress annotations.
  • The alternative solutions have too much boiler-plate, or in most cases, without any real advantage vs AsyncTask.
  • We didn't want to re-invent the wheel.
  • We didn't want to fear the day it will finally be removed.
  • Refactoring takes too much time.

Example

Simply add below file to your project, then search for "android.os.AsyncTask" imports, and replase all to the packge you did choose for said file.

As you may already know, this is no big deal, and is basically what the well known AndroidX library does all the time.

Get AsyncTask.java file at: https://gist.github.com/top-master/0efddec3e2c35d77e30331e8c3bc725c

Top-Master
  • 7,611
  • 5
  • 39
  • 71
2

You can migrate to next approaches depends your needs

  • Thread + Handler
  • Executor
  • Future
  • IntentService
  • JobScheduler
  • RxJava
  • Coroutines (Kotlin)

[Android async variants]

yoAlex5
  • 29,217
  • 8
  • 193
  • 205
  • Simply [un-deprecate AsyncTask](https://stackoverflow.com/a/75355078/8740349) - because if it depends on our needs, we would already be using one of above, if we really didn't need `AsyncTasks`'s features ;-) – Top-Master Feb 05 '23 at 20:07
2

You can use Executors and CompletableFutures:

This is the helper class:

public class Async {

    private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

    private static final HandlerExecutor THREAD_MAIN = new HandlerExecutor(Looper.getMainLooper());

    public static <T> void execute(Supplier<T> async, Consumer<T> sync) {
        CompletableFuture.supplyAsync(async, THREAD_POOL).thenAcceptAsync(sync, THREAD_MAIN);
    }

    public static void execute(Runnable async) {
        CompletableFuture.runAsync(async);
    }

}

And here's an example on how to use it:

public static void main(String[] args) {
    String url = "https://example.com/";

    Async.execute(() -> {
        //do something async without result
    });

    Async.execute(
            () -> {
                //do something async and return result
                try {
                    HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                    return connection.getResponseCode();
                } catch (Exception e) {
                    return null;
                }
            },
            (responseCode) -> {
                //do something with result on main thread
                Log.e("Async", "responseCode=" + responseCode);
            }
    );
}
nhcodes
  • 1,206
  • 8
  • 20
0

This is my code

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public abstract class AsyncTaskRunner<T> {

    private ExecutorService executorService = null;
    private Set<Callable<T>> tasks = new HashSet<>();

    public AsyncTaskRunner() {
        this.executorService = Executors.newSingleThreadExecutor();
    }
    
    public AsyncTaskRunner(int threadNum) {
        this.executorService = Executors.newFixedThreadPool(threadNum);
    }


    public void addTask(Callable<T> task) {
        tasks.add(task);
    }

    public void execute() {
        try {
            List<Future<T>> features = executorService.invokeAll(tasks);

            List<T> results = new ArrayList<>();
            for (Future<T> feature : features) {
                results.add(feature.get());
            }
            this.onPostExecute(results);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            this.onCancelled();
        } finally {
            executorService.shutdown();
        }

    }

    protected abstract void onPostExecute(List<T> results);

    protected void onCancelled() {
        // stub
    }

}

And usage example. Extends the AsyncTaskRunner class,

class AsyncCalc extends AsyncTaskRunner<Integer> {

    public void addRequest(final Integer int1, final Integer int2) {
        this.addTask(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                // Do something in background
                return int1 + int2;
            }
        });
    }

    @Override
    protected void onPostExecute(List<Integer> results) {
        for (Integer answer: results) {
            Log.d("AsyncCalc", answer.toString());
        }
    }
}

then use it!

AsyncCalc calc = new AsyncCalc();
calc.addRequest(1, 2);
calc.addRequest(2, 3);
calc.addRequest(3, 4);
calc.execute();
wf9a5m75
  • 6,100
  • 3
  • 25
  • 59
-3

Docs says:

AsyncTask This class was deprecated in API level 30. Use the standard java.util.concurrent or Kotlin concurrency utilities instead.

You need to use Handler or coroutines instead AsyncTask.

Use Handler for Java

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        // Your Code
    }
}, 3000);

Use Handler for Kotlin

Handler(Looper.getMainLooper()).postDelayed({
    // Your Code
}, 3000)
Yuliia Ashomok
  • 8,336
  • 2
  • 60
  • 69
  • This answer executes code on the same main thread, not on a different one like it happens for AsyncTask – gxcare Feb 03 '23 at 09:09