I am new to instrumentation testing in Android. Can someone show me how i can start an async task and wait for the result to be computed ? Many of my network calls rely on AsynTasks and i need to know how we can test it ? For activities we have a getInstrumentation().waitForMonitor , what can we do for AsyncTasks ?
The AsyncTask class has a blocking get() method that will basically wait for the task to finish before it returns. It's the synchronous version of calling execute(), which means you could think of it as the background work being executed on the main thread - hence it blocks until finished.
public final Result get ()
Waits if necessary for the computation to complete, and then retrieves
its result.
Related
I am trying to make an application that constantly hits the google API to fetch the distance between two points and then process the distance and add it in db inside a loop.
I was previously using the volley but it does not waits and my function proceeds with the rest of lines of code. I need help so that the line of code waits for that method to return only if some result is received once I hit google API, then use that result in next line of code.
I'd recommend looking into coroutines. More specifically take a look at the async launcher which should return the value to an awaiting variable. Your code runs asynchronously (starting a new thread so your main UI thread doesn't block and the user can freely do as they wish) and when the call returns your code is called once again at the point where the variable will be awaiting. You could set a timer right before starting the async call and stop it after await.
You could also use withContext{} to await for a result. The code will be continued in the calling function when the coroutine returns a result.
startTimer()
val job = coroutineScope{
async{
networkCall()
}
}
job.await()
stopTimer()
or
startTimer()
coroutineScope{
launch{
withContext{
networkCall()
}
//code will continue when networkCall() has returned a result
stopTimer() //be careful, this may be called through a background thread.
}
}
Coroutines are thread-safe and lightweight so you can start as many as you want without any problems. Also, by using coroutineScope you will avoid lifecycle problems like your ui being rotated which would normally cause a network call to be resent. With coroutineScope your call will have the life span of the calling activity/fragment thus it will be cancelled or killed if your app unexpectedly decides to stop and not care for the result any longer.
Hope this helped, Panos.
If you are beginner use retrofit library to make API calls in there is option enque will call API background for you.
https://www.journaldev.com/13639/retrofit-android-example-tutorial
If you are pro go for Rxjava with Retrofit.
https://medium.com/3xplore/handling-api-calls-using-retrofit-2-and-rxjava-2-1871c891b6ae
You cannot do synchronous calls on the main thread. Blocking the UI thread on a network call for more than a specified period of time would trigger an ANR.
A couple of options would be to use an AysncTask or AsyncTaskLoader. Blocking the main thread is definitely not recommended.
AsyncTasks create a separate thread of execution while the UI thread can continue with its work.
Android applications usually start with a single thread of execution so if you block this thread then an ANR would result.
Take a look here
If you don't mind the ANRs which will not be acceptable to a user then go with using a simple HttpURLConnection but this is not recommended.
If you do not prefer the AsyncTask approach you can create a Runnable to do the background processing and then update the UI thread.
More here
You can implement a jobservice to get distance in an interval.You can view the implementation .here
At first, this is for a step counter.
My initial structure is a service keeps logging step counter value to database.
Then a async task keeps updating the value shown to user when the app is visible to user.
I planed to create a thread to periodically call the async task.
However, after digging into the official document, "async task should be created and invoked within UI thread".
The conflict now is UI thread should not be blocked vs calling async task periodically.
Or there is else a better way to implement?
Thanks for any input.
You need to derive from AsyncTask inside your UI class (service or activity).
Inside your AsyncTask (as described here) there is doInBackground which runs asynchronously and there is onPostExecute which runs inside UI thread after your asynchronous task is over.
Just put your DB operation inside doInBackground and put something like this inside onPostExecute
MyServiceClass.this.RunNextTask();
The RunNextTask method in your UI class could use the same AsyncTask to launch the next task.
I am working on async task. When i call execute() on async task it takes 1 second to call doInBackground() method of async task which I don't want. Does anyone knows how to reduce that time?
Such things are up to the System. Never assume anything about timing when working multithreaded!
Anyways, if your AsyncTask repeatedly does the same work, try using an ExecutorService which gets a Runnable as argument. The ExecutorServices don't destroy the created threads automatically but try to re-use it. That way the starttime might be reduced.
One second to call doInBackground(), or one second to return a result? The reason for using an AsyncTask is to perform longer operations asynchronously from the UI thread. Performing operations that take a while (eg. 1 second) is why they exist.
instead of execute() use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...) That way you don't need an ExecutorService.
I want to ensure that I don't slow down my app's startup time and need to start a background task that's unrelated to user input--for instance, filling a cache.
If I start an AsyncTask from my onCreate method, when will the doInBackground method actually begin to execute? (Assume a single core device)
Is it possible that Android could schedule it before onCreate/onResume has completed, or is it smart enough to recognize that the background thread shouldn't run until the UI thread is completely finished?
If you look at AsyncTask source code you will see that it is just using ThreadPoolExecutor or serial executor for running tasks. Default internal behavior depends on Android version (from AsyncTask docs):
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
But anyway doInBackground execution is not connected with Activity lifecycle so AsyncTask may be executed at almost any time. This depends only on how many tasks you have already started, on default Executor which is used by AsyncTask and on thread scheduler.
I usually use AsyncTasks in onCreate() like this:
private MySuperSpecialTask mySuperSpecialTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(...);
// [...]
mySuperSpecialTask = new MySuperSpecialTask();
mySuperSpecialTask.execute();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mySuperSpecialTask != null) {
mySuperSpecialTask.cancel(true);
}
}
This makes sure that everything is initialized before the task gets started.
actually strictly speaking there is no execution order of your UI code and starting the asynctask I found out. Normally one does not experience this, however, if your UI thread takes longer for some reason, eg waiting for external input etc, the asynctask might have gotten started BEFORE UI code has finished.
Writing UI code is just a request to the Android system and this waits in the execution loop. So if asynctask starts before that because there are enough ressources (or as mentioned UI thread is delayed for whatever reason) there is no execution order guarantee.
One easy way to enforce this is - in case you don't mind and you can be sure that it is suffiencient - delay the starting of the asynctask with ScheduledExecutorService or a "cleaner" way would be to implement some kind of gate keeper that waits for a flag to be set to true and then start the asynctask. Or you may even have a while-loop at the beginning of your asynctask that waits for the flag to be set to true, like in many communication situations with external devices.
The flag would be set to true AFTER you can be (normally) sure that your UI has finished.
I am writing an Android Activity test case by extending ActivityInstrumentationTestCase2. The Activity I am testing offloads work to a Loader. The Activity itself is the LoaderCallback.
The problem is that the test case finishes before the Loader completes its work (because the Loader is obviously running on another thread than the test case). How can I get the test case to wait until the Loader has finished its work.
One thought I had was to join to the underlying Loader thread. However, I can't seem to find a way to get access to the underlying thread. Also, the Loader thread might not start immediately so not sure this is the right approach.
The other though I had was to register a LoaderListener in the test case, but it seems a particular Loader can only have one LoaderListener.
You could set a max timeout. Check for a null value in the loader every so often until you reach the max timeout. Once the max timeout is set have the test fail because the loader would not load.
Try to do it with mutex or ReentrantLock.
You need to use some Java synchronization method between the thread the test case is running in, and the background thread or action you are waiting to complete.
I have used a countdown latch.
In your code under test (Activity in my case)
Initialize it when your activity is created
private final CountDownLatch signal = new CountDownLatch(1);
When the Loader finishes, have your code signal it's done:
signal.countDown();
I provide a getter for the latch in my code under test
public CountDownLatch getSignal() {
return signal;
}
In your test:
start the activity (which starts the background thread)
MainActivity activity = getActivity();
get the latch to wait on
CountDownLatch signal = activity.getSignal();
do other stuff, then wait for the background task to end
if (!signal.await(30, TimeUnit.SECONDS)) {
fail("Timed out waiting for the background task to complete");
}
This works for stuff being in done in background threads, AsyncTasks etc that are started by the onCreate() method of your activity...