Zeeshan
Zeeshan

Reputation: 12421

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


    }

Upvotes: 249

Views: 233327

Answers (19)

Vitaly
Vitaly

Reputation: 438

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(20, 128, 1,
                    TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

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

    private final AtomicBoolean mIsInterrupted = new AtomicBoolean(false);

    protected void onPreExecute(){}
    protected abstract Void doInBackground(Params... params) throws InterruptedException;
    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));
            }
        });
    }

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

    public boolean isCancelled(){
        return isInterrupted();
    }

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

    protected boolean isInterrupted() {
        return mIsInterrupted.get();
    }

    protected void setInterrupted(boolean interrupted) {
        mIsInterrupted.set(interrupted);
    }
}

Example of using this class:

public class MySearchTask extends AsyncTaskExecutor<String> {

    @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");

Upvotes: 6

Murat Gungor
Murat Gungor

Reputation: 125

WorkManager is the way to go

OneTimeWorkRequest mywork = new OneTimeWorkRequest.Builder(FlipMediaPeriodicWorker.class)
                .setInitialDelay(activity.currentMedia.timing, TimeUnit.SECONDS)
                .build(); 
WorkManager.getInstance(activity).enqueue(mywork);

You can make it recursive to repeat tasks for less than 15 minutes.

Upvotes: 1

nhcodes
nhcodes

Reputation: 1964

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

Upvotes: 4

Top-Master
Top-Master

Reputation: 8751

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

Upvotes: 6

Yuliia Ashomok
Yuliia Ashomok

Reputation: 8598

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)

Upvotes: -3

Sergio
Sergio

Reputation: 30665

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

Upvotes: 51

Kashfa Khan
Kashfa Khan

Reputation: 2493

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

Upvotes: 216

Mayank Kumar Chaudhari
Mayank Kumar Chaudhari

Reputation: 18578

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

Upvotes: 61

Attaullah
Attaullah

Reputation: 4021

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

Upvotes: 4

milan pithadia
milan pithadia

Reputation: 870

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

Upvotes: 17

wf9a5m75
wf9a5m75

Reputation: 6158

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

Upvotes: 0

yoAlex5
yoAlex5

Reputation: 34255

You can migrate to next approaches depends your needs

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

[Android async variants]

Upvotes: 2

Mohamed Ben Romdhane
Mohamed Ben Romdhane

Reputation: 1706

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

Upvotes: 2

Kishan Donga
Kishan Donga

Reputation: 3193

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

Upvotes: 2

Honza Johny Pejsar
Honza Johny Pejsar

Reputation: 121

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.

Upvotes: 3

Kumar
Kumar

Reputation: 127

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

Upvotes: 9

Anoop M Maddasseri
Anoop M Maddasseri

Reputation: 10549

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

Upvotes: 10

Wahab Khan Jadon
Wahab Khan Jadon

Reputation: 1176

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.

Upvotes: 3

EpicPandaForce
EpicPandaForce

Reputation: 81549

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

Upvotes: 128

Related Questions