Chain a series of asynchronous calls - java

I have a series of asynchronous operations
private void doSomething(){
get("/something", new Callback(){
void onComplete(String data){
updateUi(something, data);
doSomethingElse();
}
});
}
private void doSomethingElse(){
get("/something/else", new Callback(){
void onComplete(String data){
updateUi(somethingElse, data);
doYetAnotherThing();
}
});
}
private void doYetAnotherThing(){
get("/yet/another/thing", new Callback(){
void onComplete(String data){
updateUi(yetAnotherThing, data);
allDone();
}
});
}
This suffers from few problems:
Cannot reuse any of the callbacks elsewhere since each is intrinsically tied to the "next step"
Re-ordering operations or inserting another operation is non-intuitive and involves jumping all over the place.
I have looked at the following options to mitigate this:
ExecuterService#invokeAll - I don't see how this solution can be used without blocking.
RxJava - I would prefer to avoid such a paradigm shift in my application if I can!
Guava's ListenableFutures and its transform method. I saw this referred to in few places around the interwebs nut I honestly don't see how this would solve my problem.
So, the question is: What would be a good pattern to chain a series of asynchronous calls in Java? Looking for a solution that works with Java 7 since I need this for an Android app.

There certainly is some guessing involved, regarding the actual intention and use-case where you encountered this problem. Additionally, it is not entirely clear what something, somethingElse and yetAnotherThing are (where they come from and where they should go).
However, based on the information that you provided, and as an addition to (or rather extension or generalization of) the answer by slartidan: The difference between these dummy calls that you sketched there seem to be
The String argument that is passed to the get method
The Callback that is called
Which method is executed next
You could factor out these parts: The String argument and the Callback could be passed as parameters to a general method that creates a Callable. The sequence of the calls could simply be defined by placing these Callable objects into a list, in the appropriate order, and execute them all with a single threaded executor service.
As you can see in the main method of this example, the sequence of calls can then be configured rather easily:
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChainedAsyncTest {
public static void main(String[] args) throws InterruptedException {
ChainedAsyncTest t = new ChainedAsyncTest();
ExecutorService e = Executors.newFixedThreadPool(1);
e.invokeAll(Arrays.asList(
t.call("/something", t.somethingCallback),
t.call("/something/else", t.somethingElseCallback),
t.call("/yet/another/thing", t.yetAnotherThingCallback),
t.allDone()));
}
private Callback somethingCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("something", data);
}
};
private Callback somethingElseCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("somethingElse", data);
}
};
private Callback yetAnotherThingCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("yetAnotherThing", data);
}
};
private Callable<Void> call(
final String key, final Callback callback) {
return new Callable<Void>() {
#Override
public Void call() {
get(key, callback);
return null;
}
};
}
private Callable<Void> allDone() {
return new Callable<Void>() {
#Override
public Void call() {
System.out.println("allDone");
return null;
}
};
}
interface Callback
{
void onComplete(String data);
}
private void get(String string, Callback callback) {
System.out.println("Get "+string);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.onComplete("result of "+string);
}
private void updateUi(String string, String data) {
System.out.println("UpdateUI of "+string+" with "+data);
}
}
(The example uses invokeAll, which blocks until all tasks have been executed. This could be solved differently to be really non-blocking at the call site. The main idea is to create a list of the tasks, which are all created by the same method call)

Spontainious thought: You could define the chained calls as a method parameter to make your methods reusable. Here is my example code:
public class Scribble {
final Callback step1 = new Callback() {
void onComplete(String string) {
doSomethingElse(step2);
};
};
final Callback step2 = new Callback() {
void onComplete(String string) {
doYetAnotherThing(step3);
};
};
final Callback step3 = new Callback() {
void onComplete(String string) {
allDone();
}
};
private void start() {
doSomething(step1);
}
private void doSomething(final Callback externalCallback) {
get("/something", new Callback() {
void onComplete(String data) {
updateUi(something, data);
externalCallback.onComplete(data);
}
});
}
private void doSomethingElse(final Callback externalCallback) {
get("/something/else", new Callback() {
void onComplete(String data) {
updateUi(somethingElse, data);
externalCallback.onComplete(data);
}
});
}
private void doYetAnotherThing(final Callback externalCallback) {
get("/yet/another/thing", new Callback() {
void onComplete(String data) {
updateUi(yetAnotherThing, data);
externalCallback.onComplete(data);
}
});
}
// - the code below is only to make everything compilable -
public class Callback {
void onComplete(String string) {
}
}
private Object something;
protected Object somethingElse;
protected Object yetAnotherThing;
protected void allDone() {
System.out.println("Scribble.allDone()");
}
protected void updateUi(Object yetAnotherThing2, String data) {
System.out.println("Scribble.updateUi()"+data);
}
private void get(String string, Callback callback) {
System.out.println("get "+string);
callback.onComplete(string);
}
public static void main(String[] args) {
new Scribble().start();
}
}

I totally support the approved answer, but I'm also tossing in something I created for these types of problems that comes in handy when you start adding conditional logic within your chain of asynchronous actions. I recently fermented this into a simple library (jasync-driver).
Here is how you'd wire up your example. As you can see, each task has no knowledge of the task that follows. In contrast to the approved answer, the chaining of the tasks is done through a simple synchronous (...looking) method body instead of a list.
public void doChainedLogic() {
final AsyncTask<Void, Void> doSomething = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something", new Callback() {
public void onComplete(String data) {
updateUi(something, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doSomethingElse = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something/else", new Callback() {
public void onComplete(String data) {
updateUi(somethingElse, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doYetAnotherThing = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/yet/another/thing", new Callback() {
public void onComplete(String data) {
updateUi(yetAnotherThing, data);
resultHandler.reportComplete();
}
});
}
};
// This looks synchronous, but behind the scenes JasyncDriver is
// re-executing the body and skipping items already executed.
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
driver.execute(doSomethingElse);
driver.execute(doYetAnotherThing);
}
});
}
Now here's a tweak to the example that includes some conditional logic that depends upon an asynchronous result:
final AsyncTask<Void, String> checkSomething = new AsyncTask<Void, String>() {
#Override
public void run(Void arg, final ResultHandler<String> resultHandler) {
get("/check/something", new Callback() {
public void onComplete(String data) {
resultHandler.reportComplete(data);
}
});
}
};
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
if ("foobar".equals(driver.execute(checkSomething))) {
driver.execute(doSomethingElse);
}
driver.execute(doYetAnotherThing);
}
});
As you can see, asynchronous conditional logic is as simple as writing a standard if statement.

Related

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

Unit Testing In Network With Using Volley in Android

I am trying to test functions from my Presenter Class. In below, I can reach getSomeThing() function however, I cannot reach the getData() and getError() functions.
Volley functions are not working in unit tests. Further help would be highly appreciated as I am struggling with this for over a week.
Below is my Presenter Class, Presenter Listener and Test Function.
my Presenter Class:
public abstract class SomePresenter implements BasePresenterListener {
private static final String sTAG = SomePresenter.class.getSimpleName();
private Context context;
private Integer testInteger;
protected SomePresenter(Context context, Integer testInteger) {
this.context = context;
this.testInteger = testInteger;
onResponse();
}
#Override
public void onResponse() {
try {
Thread.sleep(1000);
getSomeThing();
} catch (InterruptedException e) {
e.printStackTrace();
}
final GetRequest<SomeResponse> someResponseRequest =
ApiRequests.getSomeResponse(
new Response.Listener<SomeResponse>() {
#Override
public void onResponse(SomeResponse response) {
getData(response);
}
}
,
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(Constant.NETWORK_ERROR);
getError(errorResponse);
}
}
);
NetworkInstance.addRequest(context, poiResponseGetRequest, sTAG);
}
public static void cancelRequest(Context context) {
NetworkInstance.cancelAllRequests(context, sTAG);
}
protected abstract void getSomeThing();
protected abstract void getData(SomeResponse response);
protected abstract void getError(ErrorResponse response);
}
my BasePresenter Class:
public interface BasePresenterListener {
void onResponse();
}
my Unit Test Function:
#Test
public void test() throws InterruptedException {
new SomePresenter(mockContext, 107){
#Override
protected void getData(PoiResponse response) {
SomeLogger.debug("getData works");//this is not called.
}
#Override
protected void getSomeThing() {
SomeLogger.debug("getSomeThing works!");//this is called.
}
#Override
protected void getError(ErrorResponse response) {
SomeLogger.debug("ErrorResponse works!"); //this is not called.
}
};
}
I have looked below links none of them solved my problem.
Unit testing a network response. Works when debugging, not when actually running
Android Unit test with Volley
In my case is I can reach the getSomething() function from unit test but I cannot reach the getData() nor getError() functions because Volley does not seem to work in unit tests.
All, getSomething(), getData(), getError() functions are callback functions, I can reach the getSomeThing() function but I cannot reach the getData() and getError() functions.

Synchronize Multiple Async Requests

Given an async service which should be closed upon completion. I would like to execute multiple instances of a requests. When all requests are done I want to close the service. I'm wondering what's the best way to achieve that. So here is the code demonstrating the problem but without actually closing the service:
class Service implements Closeable {
public Service() {/*...*/}
public ListenableFuture<Integer> processRequest(Integer param) {/*...*/}
#Override
public void close() {/*...*/}
}
public void proccessRequests(ArrayList<Integer> params) {
Service svc = new Service();
for (Integer param : params) {
final ListenableFuture<Integer> res = svc.processRequest(param);
}
}
I'm considering different options to close the service:
Use CountDownLatch this way:
public void processRequests(ArrayList<Integer> params) {
Service svc = new Service();
CountDownLatch latch = new CountDownLatch(params.size());
for (Integer param : params) {
final ListenableFuture<Integer> res = svc.processRequest(param);
Futures.addCallback(res, new FutureCallback<Integer>() {
#Override
public void onSuccess(Integer integer) {
latch.countDown();
if (latch.getCount() == 0) {
svc.close();
}
}
#Override
public void onFailure(Throwable throwable) {
latch.countDown();
if (latch.getCount() == 0) {
svc.close();
}
}
});
}
}
Use CountDownLatch this way:
public void processRequests(ArrayList<Integer> params) {
Service svc = new Service();
CountDownLatch latch = new CountDownLatch(params.size());
for (Integer param : params) {
final ListenableFuture<Integer> res = svc.processRequest(param);
Futures.addCallback(res, new FutureCallback<Integer>() {
#Override
public void onSuccess(Integer integer) {
latch.countDown();
}
#Override
public void onFailure(Throwable throwable) {
latch.countDown();
}
});
}
latch.await();
svc.close();
}
Similar to first option but using AtomicInteger.
What's the best way to achieve that? first, second, third, none of these?
Your first solution with CountDownLatch looks fine, but there are some other methods.
Starting from version 20.0 Futures class has a whenAllComplete method designed exactly for that purpose. Using it you can write:
Service svc = new Service();
Futures.whenAllComplete(params.stream().map(svc::processRequest).collect(Collectors.toList())).call(() -> {
svc.close();
return null;
}, ForkJoinPool.commonPool());
You can also use Java 8 CompletableFuture class that has a similar method allOf:
CompletableFuture.allOf(params.stream().map(svc::processRequest).toArray(CompletableFuture[]::new))
.thenAccept(v -> svc.close());
but in this case you have to make your Service return a CompletableFuture.

How to properly convert Listeners to Reactive (Observables) using RxJava?

I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.

Obtaining reference to original Scheduler

I have the following RxJava Observable:
final class MapBitmapObservable {
static Observable<Bitmap> create(#NonNull final MapView mapView) {
return Observable.create(new Observable.OnSubscribe<Bitmap>() {
#Override
public void call(final Subscriber<? super Bitmap> subscriber) {
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(#NonNull final GoogleMap googleMap) {
googleMap.snapshot(new GoogleMap.SnapshotReadyCallback() {
#Override
public void onSnapshotReady(#Nullable final Bitmap bitmap) {
if (bitmap != null) {
subscriber.onNext(bitmap);
subscriber.onCompleted();
} else {
subscriber.onError(new MapSnapshotFailedException());
}
}
});
}
});
}
});
}
private MapBitmapObservable() {
}
}
The MapView method getMapAsync must be called on the main thread to avoid this exception:
java.lang.IllegalStateException: getMapAsync() must be called on the main thread
at com.google.android.gms.common.internal.zzx.zzcD(Unknown Source)
at com.google.android.gms.maps.MapView.getMapAsync(Unknown Source)
at com.github.stkent.bugshaker.email.screenshot.maps.MapBitmapObservable$1.call(MapBitmapObservable.java:42)
at com.github.stkent.bugshaker.email.screenshot.maps.MapBitmapObservable$1.call(MapBitmapObservable.java:37)
at rx.Observable.unsafeSubscribe(Observable.java:8098)
...
Assume the MapBitmapObservable is used as part of an Observable chain in which previous and subsequent operations are potentially long-running and should be executed off the main thread. A simplified example could look like this:
Observable.just(activity)
.flatmap(new Func1<Activity, Observable<MapView>>() {
#Override
public Observable<Bitmap> call(#NonNull final Activity activity) {
return ExpensiveToCreateObservable.create(activity);
}
})
.flatmap(new Func1<MapView, Observable<Bitmap>>() {
#Override
public Observable<Bitmap> call(#NonNull final MapView mapView) {
return MapBitmapObservable.create(mapView);
}
})
.flatmap(new Func1<Bitmap, Observable<Uri>>() {
#Override
public Observable<Uri> call(#NonNull final Bitmap bitmap) {
return SomeOtherExpensiveToCreateObservable.create(bitmap);
}
})
.subscribeOn(Schedulers.io())
.subscribe();
(although it should be noted that in my actual application, the chaining is spread across several different methods). I would like to:
make sure that MapView.getMapAsync is called on the main thread;
allow the second long-running operation to execute on the original Scheduler, whatever that may have been (Schedulers.io(), Schedulers.computation(), etc.)
In my mind, pseudocode to achieve this would look something like:
Observable.just(activity)
.flatmap(new Func1<Activity, Observable<MapView>>() {
#Override
public Observable<Bitmap> call(#NonNull final Activity activity) {
return ExpensiveToCreateObservable.create(activity);
}
})
.observeOn(AndroidSchedulers.mainThread()) // This is real, and resolves bullet 1.
.flatmap(new Func1<MapView, Observable<Bitmap>>() {
#Override
public Observable<Bitmap> call(#NonNull final MapView mapView) {
return MapBitmapObservable.create(mapView);
}
})
.observeOn(/* Some way of referencing the thread on which I originally subscribed, to resolve bullet 2. */)
.flatmap(new Func1<Bitmap, Observable<Uri>>() {
#Override
public Observable<Uri> call(#NonNull final Bitmap bitmap) {
return SomeOtherExpensiveToCreateObservable.create(bitmap);
}
})
.subscribeOn(Schedulers.io()) // I do not want to rely on knowledge of the Scheduler type used at this call-site.
.subscribe();
Is this possible?
From the observeOn() documentation:
ObserveOn, on the other hand, affects the thread that the Observable will use below where that operator appears. For this reason, you may call ObserveOn multiple times at various points during the chain of Observable operators in order to change on which threads certain of those operators operate.
So as mentioned by Aaron He, you could keep some reference to the Scheduler you are using use it on the latter "observeOn".
Another approach to do this that I sometimes use, is to remove both "observeOn" function, and make sure View items are being handled on UI thread by Activity.runOnUiThread. Something like -
static Observable<Bitmap> create(#NonNull final Activity activity,#NonNull final SomeObject someObject) {
return Observable.create(new Observable.OnSubscribe<Pair<Activity,SomeObject>>() {
#Override
public void call(final Subscriber<? super Pair<Activity,SomeObject>> subscriber) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
someObject.doStuff();
}
});
}
});
}

Categories

Resources