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) ;
}
}
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
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>());
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();
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:
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
}
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
}
)
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();
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
Here I created a Alternative for AsyncTask using Coroutines which can be used same as AsyncTask without changing much code base in your project.
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();
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();
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.
I actually wrote two Medium stories about it:
AsyncTas is deprecated now what
AsyncTas is deprecated now what part 2
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.
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");
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();
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.
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();
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();
You can migrate to next approaches depends your needs
Thread + Handler
Executor
Future
IntentService
JobScheduler
RxJava
Coroutines (Kotlin)
[Android async variants]
My answer is similar to the others, but it is easier to read imo.
This is the class:
public class Async {
private static final ExecutorService executorService = Executors.newCachedThreadPool();
private static final Handler handler = new Handler(Looper.getMainLooper());
public static <T> void execute(Task<T> task) {
executorService.execute(() -> {
T t = task.doAsync();
handler.post(() -> {
task.doSync(t);
});
});
}
public interface Task<T> {
T doAsync();
void doSync(T t);
}
}
And here's an example on how to use it:
String url;
TextView responseCodeText;
Async.execute(new Async.Task<Integer>() {
#Override
public Integer doAsync() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
return connection.getResponseCode();
} catch (IOException e) {
return null;
}
}
#Override
public void doSync(Integer responseCode) {
responseCodeText.setText("responseCode=" + responseCode);
}
});
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();
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 did not 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
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)
Related
I'm using an executor for background operations. I have a method that takes data from a Room Database and returns a string, so that I can send it from the repository into a viewmodel into activity.
How can I return a string in the method while there is a runnable in it? Please see the following code for a better description:
public String singleLoad(final int id){
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.execute(new Runnable() {
#Override
public void run() {
favNewsDao.loadSingle(id);
}
});
return favNewsDao.loadSingle(id);
}
The return gives an exception, saying that it cannot access the database on the Main Thread. How can I get a string from this method, like I have in this ViewModel class
public String singleLoad(int id) {
return repository.singleLoad(id);
}
Instead of using an Executor you can use an ExecutorService and submit a Callable. More information here: https://developer.android.com/reference/java/util/concurrent/ExecutorService.html#submit(java.util.concurrent.Callable%3CT%3E)
First Approach
In Repository class, use CountDownLatch with a count value of 1, and with until it reaches 0 to return back the correct result this can be achieved by using await() of this CountDownLatch which allows to urge executing the underlying code until the latch count value reaches 0.
CountDownLatch mLatch;
String singleLoad;
public String singleLoad(final int id){
mLatch = new CountDownLatch(1); // latch count is 1
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.execute(new Runnable() {
#Override
public void run() {
singleLoad = favNewsDao.loadSingle(id);
mLatch.countDown(); // Now you can allow returning back the result (id)
}
});
// Don't return now and wait until the Executer is done
try {
// Application's main thread awaits, till the
// CountDownLatch count value reaches 0
mLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mId;
}
UPDATE
As first approach might have memory leak, here is a second approach by using a listener instead of CountDownLatch.
Second Approach
Here I am triggering a listener whenever the needed String is returned back from Room database to the Repository class; the listener is registered in the activity, cascaded to ViewModel, and then to the Repository.
The listener has a callback that retrieves the returned String from database which is eventually returned back to the activity.
Dao interface
#Dao
public interface MyDao {
...
#Query("SELECT text FROM notes WHERE id = :id") // change types according to your database
String loadSingle(int id);
}
Repository
public class AppRepository {
// ... non-relevent code is omitted
private static Executor executor = Executors.newSingleThreadExecutor();
public interface OnTextListener {
void onTextReceived(String text);
}
public void getNoteText(int id, OnTextListener listener) {
executor.execute(() -> {
String text = mDb.noteDao().loadSingle(id); // mDb is the database instance in repository
// trigger the listener in the ViewModel
listener.onTextReceived(text);
});
}
}
ViewModel
public class MainViewModel extends AndroidViewModel {
// ... non-relevent code is omitted
public void getNoteText(int id, AppRepository.OnTextListener listener) {
mRepository.getNoteText(id, listener);
}
}
Activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ... non-relevent code is omitted
// Retrieve single data from Room database
int id = 39;
mViewModel.getNoteText(id, new AppRepository.OnTextListener() {
#Override
public void onTextReceived(String text) {
// The retrieved text from Room database
Log.d(TAG, "onTextReceived: " + text);
new Handler(Looper.getMainLooper()) {
}.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
}
});
}
}
in this code excerpt I am trying to process a bunch of data, but it can't be on the UI thread otherwise the experience is a possible ANR. I thought this was easily done with rxJava2, however, the data processing always runs on the main thread.
Data loading is triggered in the "presenter" like this:
void loadHistoricalDataFromFile(String filename){
view.showProgressDialog();
addDisposable(
model.loadHistoricalDataObservable(filename)
.subscribeOn(rxSchedulers.runOnBackground())
.observeOn(rxSchedulers.mainThread())
.subscribe(loadedSuccessfully -> {
view.hideProgressDialog();
if (loadedSuccessfully){
view.showSnackBar(R.string.simulator_loaded_data_success, LENGTH_SHORT);
} else {
view.showSnackBar(R.string.simulator_loaded_data_fail, LENGTH_INDEFINITE);
}
}));
}
As you can see, I've used .subscribeOn(rxSchedulers.runOnBackground())
rxSchedulers.runOnBackground() is implemented as follows :
public class AppRxSchedulers implements RxSchedulers {
public static Executor backgroundExecutor = Executors.newCachedThreadPool();
public static Scheduler BACKGROUND_SCHEDULERS = Schedulers.from(backgroundExecutor);
public static Executor internetExecutor = Executors.newCachedThreadPool();
public static Scheduler INTERNET_SCHEDULERS = Schedulers.from(internetExecutor);
public static Executor singleExecutor = Executors.newSingleThreadExecutor();
public static Scheduler SINGLE_SCHEDULERS = Schedulers.from(singleExecutor);
#Override
public Scheduler runOnBackground() {
return BACKGROUND_SCHEDULERS;
}
#Override
public Scheduler io() {
return Schedulers.io();
}
#Override
public Scheduler compute() {
return Schedulers.computation();
}
#Override
public Scheduler mainThread() {
return AndroidSchedulers.mainThread();
}
#Override
public Scheduler internet() {
return INTERNET_SCHEDULERS;
}
#Override
public Scheduler single() {
return SINGLE_SCHEDULERS;
}
}
the Single.Just() is implemented as follows
Single<Boolean> loadHistoricalDataObservable(String filename){
return Single.just(loadHistoricalData(filename));
}
private Boolean loadHistoricalData(String filename){
boolean successful = false;
String json = FileUtils.readFileAsStringFromExtRam(filename);
if (json.length() > 0) {
Gson gson = new Gson();
historicPriceList = null;
historicPriceList = gson.fromJson(json, new TypeToken<List<HistoricPrice>>(){}.getType());
successful = true;
Timber.d("Successfully loaded file - recreated %d records", historicPriceList.size());
} else {
Timber.d("Failed to load file");
}
return successful;
}
the major problem is that whenever I hit a breakpoint within loadHistoricalData() I can see it runs on the main thread. It absolutely has to be on another thread. How is this possible ?
The problem is here Single.just(loadHistoricalData(filename));
You are calling the function immediately and then you are passing its result to Single.just();
You need to change it to something like this:
Single.fromCallable(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return loadHistoricalData(filename);
}
});
So it will look like this:
Single<Boolean> loadHistoricalDataObservable(String filename){
return Single.fromCallable(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return loadHistoricalData(filename);
}
});
}
Single.just statement itself always runs from thread it's called from.
You need use this to run your operations on different thread:
Single.create<Boolean> {
val data = loadHistoricalData(*****)
it.onSuccess(data)
}
Im working with the in-memory database, and doing some simple tasks like writing in some movies, then reading them out and displaying them. Im using RoomPersistance and i have some repositories set up. My problem:
Here i am getting the movies from a response, and inserting them in a database through the insertMovie method.
for (OMDBItem movie : response.body().getItems())
{
omdbItemRepository.insertMovie(movie);
}
This method looks like this:
public void insertMovie(OMDBItem movie){
AsyncTask<Void,Void,Void> atask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
movieDataBase.movieDao().insert(movie);
return null;
}
}.execute();
}
then i have this piece of code:
for (OMDBItem movie : response.body().getItems())
{
omdbItemRepository.insertMovie(movie);
}
lista_filmovi=omdbItemRepository.getAllMovies();
and getAllMovies() is a similar method that looks like this:
public List<OMDBItem> getAllMovies(){
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... voids) {
lista_filmovi=movieDataBase.movieDao().getAllMovies();
return null;
}
}.execute();
return lista_filmovi;
}
The problem is that sometimes, this method getAllMovies returns me the movies i want, but sometimes it just returns null. And it only returns movies when i put some break-points and run it in the debugger. My quess is that by running it in the debugger and clicking though the methods, im giving the insertMovie(movie) AsyncTasks more time to do its job, and when getAllMovies() gets called, it gives me a good result. So basically the question is, is there anyway i can make the getAllMovies() AsyncTask not start until the insertMovie() AsyncTasks have finished. I know i can maybe put an onPostExecute in insertMovie(), but i want these methods sepereated ( i dont want to call getAllMovies() everytime after insertMovie()). Any solution?
You have a few problems in your code.
The first is that you need to wait for all the movies to be written in the database to start the reading back. Then in the reading you cannot just return the value of lista_filmovi as the reading will be async so the returned value will not be there when you will try to read it.
An example Async task to write movies could be:
public static class InsertMovie extends AsyncTask<OMDBItem,Void,Void> {
private final Database movieDataBase;
public InsertMovie(Database movieDataBase) {
this.movieDataBase = movieDataBase;
}
#Override
protected Void doInBackground(OMDBItem... movies) {
for (OMDBItem movie : movies)
movieDataBase.movieDao().insert(movie);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// data is stored
}
}
To write the movies use the statement:
new InsertMovie(movieDataBase).execute(movies);
You shall not attempt to read the data until the OnPostExecute is called. There are various ways to do that but the simpler could be to just start the reading there.
And then to read it back:
public static class GetAllMovies extends AsyncTask<Void,Void,List<OMDBItem>> {
private final Database movieDataBase;
public GetAllMovies(Database movieDataBase) {
this.movieDataBase = movieDataBase;
}
#Override
protected List<OMDBItem> doInBackground(Void... voids) {
return movieDataBase.movieDao().getAllMovies();
}
#Override
protected void onPostExecute(List<OMDBItem> allMovies) {
// post the result to your activity
}
}
Again the result will be available in the OnPostExecute and you can't access it before that method is called.
The best ways to fit this in your Activity then varies. I suggest using an AndroidViewModel and get the result as notifications on LiveData objects. In this case you do not even need to use AsyncTask as you can just post the results in the LiveData.
Start from an AndroidViewModel like this:
/** ViewModel providing additional features to ease Room DB access */
public class RoomViewModel extends AndroidViewModel {
/** Thread executing Room operations */
private static class RoomThread extends Thread {
/** Queue of tasks pending execution */
private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
/** Set to false to stop */
private boolean running = true;
/** Send this to stop the execution */
private Runnable STOP = new Runnable() {
#Override
public void run() {
running = false;
}
};
#Override
public void run()
{
while (running) {
try {
// execute next in line, when available
tasks.take().run();
} catch (InterruptedException e) {
// this should not happen
return;
}
}
}
}
/** Executes backround Room requests in order */
private RoomThread roomThread = new RoomThread();
public RoomViewModel(#NonNull Application application) {
super(application);
// start the background execution thread
roomThread.start();
}
/**
* Queues the specified Runnable for execution
* #param runnable The Runnable to be executed in background
*/
protected void execute(Runnable runnable)
{
roomThread.tasks.offer(runnable);
}
#Override
protected void onCleared() {
// queue the stop request
execute(roomThread.STOP);
super.onCleared();
}
}
This helps you as you will have just a single background thread for DB access and so the operations will be ordered.
In your MovieViewModel extending RoomViewModel you can then use:
// write the movies
execute(new Runnable() {
#Override
public void run() {
for (OMDBItem movie : movies) movieDataBase.movieDao().insert(movie);
}
});
and
// read the movies
execute(new Runnable() {
#Override
public void run() {
allMovies.postValue(movieDataBase.movieDao().getAllMovies());
}
});
In the Activity you can observe the allMovies as MutableLiveData<List<OMDBItem>> and get notification on when new data is available to show it.
I am creating Android application using MVP pattern.
For that I am using Retrofit 2 and RxJava. App works fine
But in unit testing I am getting weird error.Same test code sometimes passes, sometimes fails.
Error displays with this message
Wanted but not invoked:
albumView.showProgress();
-> at kz.afckairat.kairat.media.AlbumPresenterTest.checkGetPhotoAlbums(AlbumPresenterTest.java:66)
Actually, there were zero interactions with this mock.
Test class
public class AlbumPresenterTest {
enter code here
private MediaService mediaService;
private AlbumView albumView;
private AlbumPresenterImpl photoAlbumPresenter;
#Before
public void setUp() throws Exception {
albumView = mock(AlbumView.class);
mediaService = mock(MediaService.class);
photoAlbumPresenter = new AlbumPresenterImpl(albumView, mediaService, MediaType.PHOTO);
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
#Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
}
#After
public void tearDown() {
RxAndroidPlugins.getInstance().reset();
}
#Test
public void checkGetPhotoAlbums() {
List<Album> albums = getAlbumList();
when(mediaService.getPhotoAlbums()).thenReturn(Observable.just(albums));
photoAlbumPresenter.getAlbums();
verify(albumView).showProgress();
verify(albumView).showAlbums(albums);
verify(albumView).hideProgress();
}
#Test
public void checkGetPhotoAlbumError() {
String msg = "Error";
when(mediaService.getPhotoAlbums()).thenReturn(Observable.error(new IOException(msg)));
photoAlbumPresenter.getAlbums();
verify(albumView).showProgress();
verify(albumView).showError(msg);
verify(albumView).hideProgress();
}
private List<Album> getAlbumList() {
List<Album> albums = new ArrayList<>();
Album album = new Album(1, "Test1", "test1.jpg", "01.01.2016", 2);
albums.add(album);
album = new Album(2, "Test2", "test2.jpg", "01.01.2016", 2);
albums.add(album);
return albums;
}
}
Presenter class which is tested
public class AlbumPresenterImpl implements AlbumPresenter {
private AlbumView view;
private MediaType type;
private List<Album> albums;
private MediaService mediaService;
public AlbumPresenterImpl(AlbumView view, MediaService mediaService, MediaType type) {
this.view = view;
this.mediaService = mediaService;
this.type = type;
}
#Override
public void getAlbums() {
Observable<List<Album>> observable;
if (type.equals(MediaType.VIDEO)) {
observable = mediaService.getVideoAlbums();
} else {
observable = mediaService.getPhotoAlbums();
}
observable.doOnSubscribe(view::showProgress)
.doAfterTerminate(view::hideProgress)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
albums = items;
view.showAlbums(albums);
}, throwable -> {
view.showError(throwable.getLocalizedMessage());
});
}
#Override
public void onResume() {
if (albums == null) {
getAlbums();
}
}
#Override
public void onDestroy() {
}
}
Why sometimes test don't pass?
Thanks a lot!
=================================
Update
As #Fred wrote problem was in Schedulers
public class RxSchedulersOverrideRule implements TestRule {
private final RxJavaSchedulersHook mRxJavaSchedulersHook = new RxJavaSchedulersHook() {
#Override
public Scheduler getIOScheduler() {
return Schedulers.immediate();
}
#Override
public Scheduler getNewThreadScheduler() {
return Schedulers.immediate();
}
};
private final RxAndroidSchedulersHook mRxAndroidSchedulersHook = new RxAndroidSchedulersHook() {
#Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
};
// Hack to get around RxJavaPlugins.reset() not being public
// See https://github.com/ReactiveX/RxJava/issues/2297
// Hopefully the method will be public in new releases of RxAndroid and we can remove the hack.
private void callResetViaReflectionIn(RxJavaPlugins rxJavaPlugins)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method method = rxJavaPlugins.getClass().getDeclaredMethod("reset");
method.setAccessible(true);
method.invoke(rxJavaPlugins);
}
#Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
RxAndroidPlugins.getInstance().reset();
RxAndroidPlugins.getInstance().registerSchedulersHook(mRxAndroidSchedulersHook);
callResetViaReflectionIn(RxJavaPlugins.getInstance());
RxJavaPlugins.getInstance().registerSchedulersHook(mRxJavaSchedulersHook);
base.evaluate();
RxAndroidPlugins.getInstance().reset();
callResetViaReflectionIn(RxJavaPlugins.getInstance());
}
};
}
}
Code taken from Github a link!
And in Test class
#Rule
public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule();
It seems you override the main thread scheduler with:
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
#Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
But from the code, the observables still run on the Schedulers.io() scheduler:
observable.doOnSubscribe(view::showProgress)
.doAfterTerminate(view::hideProgress)
.subscribeOn(Schedulers.io())
// ...
As you may know, the immediate scheduler executes code in the current thread, which I guess since you jump to the io scheduler it's a different one from the one the tests run on.
This will make the test run in one thread and the subscribers/observables in another. This would explain why sometimes the tests pass and sometimes they don't. There's a race condition.
Essential the easiest way is to make sure that at test time you have both observeOn and subscribeOn on Schedulers.immediate() and at run time you have the correct ones, i.e., Schedulers.io() and AndroidSchedulers.mainThread().
You can do this by overriding the schedulers, by passing them as constructors or you could even take a look at this where Dan Lew explains how to use compose to create scheduler transformers. You can then make sure your classes at run time use a proper scheduler transformer and at test time they use some transformer that puts everything on the immediate thread.
I have an async Retrofit-based API call in Android and need to wait with the DB calls until the API call finishes, so that I am sure the proper data gets entered into the DB.
I read that you can use Futures to accomplish this task, however with my current implementation I get a null pointer exception.
Below is the API method:
public Future<Void> postPrintMode(String authorization, final int userid, String deviceuid, final Map payload){
api.postPrintMode(authorization, userid, deviceuid, payload, new Callback<PrintMode>() {
#Override
public void success(PrintMode printMode, Response response) {
if (printMode.get_id() != 0) {
dbOps.writePrintMode(userid, printMode);
bus.getBus().post(new EVTNewPrintMode(printMode));
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
APIUtils.showAPIResponseBody(retrofitError);
}
});
return null;
}
And here the block where I want to ensure that the async code is executed BEFORE I continue to read the DB results.
Future<Void> f = APIExec.getInstance().postPrintMode(IConstants.authorization, IConstants.userId, IConstants.deviceUid, payload);
// here I get the null pointer exception
f.get();
// the code below needs to be executed after the postPrintMode(...) async method;
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
assertNotNull("Print Mode does not exist", printMode);
You can make your class that calls public Future<Void> postPrintMode method implement the new Callback<PrintMode> interface. After, you can your postPrintMode from it and pass a reference to itself into the method.
Here is a rough example (code not tested)
class Foo implements Callback<PrintMode> {
Future<Void> f;
public Foo(){
f = APIExec.getInstance().postPrintMode(IConstants.authorization, IConstants.userId, IConstants.deviceUid, this);
}
#Override
public void success(PrintMode printMode, Response response) {
if (printMode.get_id() != 0) {
dbOps.writePrintMode(userid, printMode);
bus.getBus().post(new EVTNewPrintMode(printMode));
}
if (f != null){
f.get();
// the code below needs to be executed after the postPrintMode(...) async method;
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
assertNotNull("Print Mode does not exist", printMode);
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
APIUtils.showAPIResponseBody(retrofitError);
}
}
Create a AsyncTaskThread class as below,
public class AsyncTaskThread extends AsyncTask<Void, Void, Void> {
Context context;
Handler myHandler;
public AsyncTaskThread( Context activityContext, Handler handler ) {
this.context = activityContext;
this.myHandler = handler;
}
#Override
protected void onPreExecute() {
// before starting thread you can pre process few things here if needed
}
#Override
protected Void doInBackground(Void... params) {
// do whatever you want to do here like calling your API and return your result
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// after doIn Background this method is called which will set the meesage object and give it back to handler
Message message = new Message();
message.obj = result;
myHandler.sendMessage(message);
}
}
call this async class as,
new AsyncTaskThread(this, new MyHandler()).execute();
and You will have to put this handler class inside the class you are putting above line, depending upon the result you get in handle you can perform further operations,
private class MyHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}