Picasso is using threads for loading images in the background. Even when loading from assets, there'a a slight delay until it shows up, which causes the pictures not to appear on a capture with spoon. I could add a 1s sleep in the test, but I was wondering if there was a better way.
I tried to set a Downloader or a RequestHandler to return the image synchronously, but I think I need to set a ExecutorService that uses the main thread or an AsyncTask (such that espresso will wait). With retrofit, we can use AsyncTask.THREAD_POOL_EXECUTOR with MainThreadExecutor but I'm not sure how to do it for picasso.
As a workaround, I wrapped picasso in an ImageUtil which won't be used during instrumentation:
DebugModule {
#Provide
ImageUtil imageUtil() {
if (isTest) {
return TestImageUtil();
} else {
return PicassoImageUtil();
}
}
}
Any suggestions?
update: in picasso's code, attempting to use an Executor instead of ExecutorService, I got stuck on service.shutdown().
I'm going to give you the general method for waiting on asynchronous tasks using espresso, because you can be sure that this will come up again.
You shouldn't use thread sleeping to wait for things to happen. This can cause flakiness, and causes your tests to be less efficient. Espresso was designed with avoiding sleep calls in mind.
You also shouldn't force something to be on the main thread that isn't normally on the main thread. If this causes an ANR your test could fail because of the unexpected dialog pop-up. There could also be a real bug that only happens while multi-threading, but now that you're forcing something to execute on the main thread, your tests could miss it.
You're on the right track swapping out a different wrapper for Picasso for testing. What you need is a way to hook on to when the request gets started (right before it goes off the main thread), and when the request gets finished. Swapping out a wrapper is one way to do accomplish that.
To get notified of when the request is finished, you can use the callback version of the into method.
Now that you have the entry and exit points of your asynchronous task, you can use the CountingIdlingResource to keep your test from moving on until the task is finished. It's as simple as incrementing the counter before the task starts, and decrementing it when it finishes.
Here's a great example of how to use that class: https://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso/sample/src/androidTest/java/android/support/test/testapp/AdvancedSynchronizationTest.java?autodive=0%2F%2F
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
I am running into a strange problem...
My application is meant to do some webservice calls on a separate thread. Once the webservice call is finished, it would navigate user to a different activity.
In the case when user press the home button or exit current activity it should terminate the webservice if the webservice call thread is still running. Hence I put a thread termination method in the OnPause state.
Here is the method block that is running inside the thread:
private Thread _webserviceThread;
void WebserviceCallThread(){
WebRestult result= WebserviceCall();
if(!result.containsError()){
RunOnUIThread(delegate{
transitionToActivityXYZ();
});
}
}
void RunThreadAction(){
_webserviceThread = new Thread(new ThreadStart(WebserviceCallThread));
_webserviceThread.Start();
}
protected override void OnPause(){
if(_webserviceThread != null && _webserviceThread.IsAlive){
_webserviceThread.Abort();
}
}
After the webservice call is done and begin the transition to another page, It gets to the OnPause state. However, in some strange cases, it would think that the thread is not finished in the OnPause state, even though the activity transition is the last line of the method.
Has anyone ran into this problem before? If so, how did you solve this problem?
Thanks!
I always use AsyncTask for this kind of thing. Not only does it abstract away the explicit thread handling and provide hooks to do everything you want here; it's also a nice way to represent a unit of work that can be used from other activities.
There's a simple example in this post part way down, but it doesn't use the generic parameters which are quite handy.
Why not use Task Parallel Library,
It is standard .NET, and with AsyncTask, it is only recommended for tasks that take less than few seconds. see the Documentation
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent
Below is an example for how to use Task Parallel Library, taken from here
private void loginWithTaskLibrary()
{
_progressDialog.Show();
Task.Factory
.StartNew(() =>
_loginService.Login("greg")
)
.ContinueWith(task =>
RunOnUiThread(() =>
onSuccessfulLogin()
)
);
}
I have a class which is used to get media file thumbs. This Loader like class starts an AsyncTask for every ImageView (is called in SomeAdapter#getView()). The task itself does a lot of things, and one of them is calling DiskLruCache, but when the SD card is unmounted, while the tasks are still running the application crashes.
I know how to register if the card state is changed.
So I need an approach how to stop all the running tasks. Any help would be nice.
just iterate through all list & use the following which will cancel all running asynctask.
if(myAsyncTask.getStatus().equals(AsyncTask.Status.RUNNING))
{
myAsyncTask.cancel(true);
}
call cancel() on each of you asynctasks, your asynctasks must check isCancelled() for returning true and if so then return from doInBackground. This is all in AsyncTask documentation.
There is one problem with your solution, AsyncTasks are known to work in parallel on some androids and to work serially on some other. Its actually not a good idea to run them in parallel. You might consider using ExecutorService as Veaceslav Gaidarji suggested.
You can try ExecutorService look here
There are nice examples - how to start async tasks, and how to stop them at any time you need.
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've got activity that has to do many things before it is visible. In proccess of loading view I have to load up bitmap/drawable that consume some time and prevents from other actions that could be done in that time. So i decide to move it to another thread. I've used Async Task, but this is not solid way of loading things. There are situations where task starts 1-2 sec after my view is shown! Is there anothe way to load bitmap/drawable that will not consume so much time and will allow to assign it to ImageView?
It is likely that you are still blocking your UI thread before executing the task. Use a logger to verify when your task is being executed.
If the task does take up a lot of time to execute then the bitmaps you are loading may be too large, in which case you should look at the down-sampling the images you are loading using the inSampleSize option with BitmapFactory.
AsyncTask runs tasks from a thread pool which might already be fully in use so it might have to keep the tasks in queue until a thread frees up to run new task. Though I doubt this is the cause of the problem.
You should maybe consider displaying a progress indicator before the actual view you want to show to make sure all tasks are done before the user sees them.
Edit
you could also use task.get(); after running all the other tasks to wait for the bitmap loader to complete before showing anything... but do try to keep the UI responding!