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
Related
I don't know is there any difference between CoroutineScope(Dispatchers.Main).launch and runOnUiThread, I think both will run on Main thread.
but still confusion is any difference there.?
Thanks.
Firstly, you can call runOnUiThread only in the context of Activity.
Secondly, you cannot call suspend functions from runOnUiThread, while you can do it in CoroutineScope(Dispatchers.Main).launch block.
Thirdly, runOnUiThread checks if the current ui thread is busy with other operations, if it is, the task is posted to an activity handler and will be executed when its turn will come.
They're different things using different technologies, and really it comes down to whether you're already using a coroutine or not. If so, just switch to the Main dispatcher when your code needs to be on the main thread. If you're not using coroutines, and you're explicitly using another thread, then you can use runOnUiThread to run some code on the main one. If you're not using coroutines or threads, then you don't need to call runOnUiThread at all!
There's nothing stopping you from using runOnUiThread from inside a coroutine - but it's not really the right tool for the job, you're stepping outside of coroutine handling unnecessarily. Plus like Steyrix says, you need access to something like an Activity to do it, which could mean holding a reference to one in a long-running coroutine when it should be garbage collected.
There are lots of other ways to get back on the main thread too, e.g. posting Runnables to a Handler (or through a View), or the postValue methods on LiveData. You don't have to switch dispatcher if there's something more concise and convenient available, it all depends on the situation
If the operations inside CoroutineScope(job+Dispatchers.Main){...} run on the main thread then how come it does not violate Android's requirement that slow (blocking) operations (Networking etc.) are not allowed to run on the main/UI thread? I can run blocking operations with this scope and the UI does not freeze at all.
I would be grateful if someone could explain what is happening under the hood. My guess is that it is similar to how JavaScript manages blocking operations with the event loop, but I struggle to find any relevant materials.
My guess is that it is similar to how JavaScript manages blocking operations with the event loop
Yes, this is correct, the event loop is essential to making coroutines work. Basically, when you write this:
uiScope.launch {
delay(1000)
println("A second has passed")
}
it compiles into code that has the same effect as this:
Handler(Looper.mainLooper()).postDelayed(1000) { println("A second has passed") }
The main concept is the continuation, an object that implements a state machine that corresponds to the sequential code you wrote in a suspendable function. When you call delay or any other suspendable function, the continuation's entry-point method returns a special COROUTINE_SUSPENDED value. Later on, when some outside code comes up with the return value of the suspendable function, it must call continuation.resume(result). This call will be intercepted by the dispatcher in charge, which will post this call as an event on the GUI event loop. When the event handler is dequeued and executed, you are back inside the state machine which figures out where to resume the execution.
You can review this answer for a more fleshed-out example of using the Continuation API.
Running blocking operations and running suspending operations on CoroutineScope(Dispatchers.Main) are two different things.
delay() is a suspending function and it is non blocking
CoroutineScope(Dispatchers.Main){
delay(6000)
}
While Thread.sleep() is blocking and calling code below will cause ANR
CoroutineScope(Dispatchers.Main){
Thread.sleep(6000)
}
I suggest you checking Kotlin coroutines talk by Roman Elizarov on Kotlinconf 2017, especially the part where he runs 100,000 delay()
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.
I have an Android service that starts and maintains a background thread.
From time to time, the background thread needs to do a callback on the main thread. I'm stumped as to how to do this.
I can't call this.runOnUiThread because "this" is an instance of Service, not Activity, and a Service doesn't have the runOnUiThread method.
I also can't create or execute an AsyncTask, because the documentation for AsyncTask says that both the constructor and the execute method must be invoked from the UI thread.
Do I need to maintain a reference to the activity that is using the service and call its runOnUiThread method, or is there another way to run something on the UI thread?
Thanks.
I'm using following code from time to time if I do not hold direct access to Activity (for a reason or another);
new Handler(Looper.getMainLooper()).post(mYourUiThreadRunnable);
For Kotlin:
Handler(Looper.getMainLooper()).post {
/*My task*/
}
If you code in Kotlin you can use coroutine with Main dispatcher:
private fun runOnUiThread(block: () -> Unit) {
CoroutineScope(Dispatchers.Main).launch { block.invoke() }
}
Of-cause coroutines should added to your project as a dependency.
Sure. See Handler. You can give to your service a handler object and when service needs to run some Runnable task on UI thread just must call handler.post(some_runnable_task). This call. Can find a example in this link 4.Tutorial: Handler.
Your activity has to can bind to the service.
http://developer.android.com/guide/components/bound-services.html
Specifically, take a look at creating a Messenger on that page. The client activity can give a messenger object that responds to messages from the service, and once received, run whatever UI code is necessary on the UI thread using a handler.
DO NOT keep the activity's reference in the service. This can lead to all sorts of memory issues.
I have a a service class which includes an Async task. In the doInBackground and onPostExecute I call some methods which are in the service class but outside the Async task. When these methods get called will they still be in the thread created by the Async task and therefore not interfering with the main UI.
To illustrate my lack of understanding a bit more should I try to get almost everything that the service class does into the Async task. For example the service starts up as the result of an alarm and in the onStartCommand sets a repeating alarm (this is as Reto Meire's Earthquake example)and creates a database. Would it make sense to move the code for these two operations into the onPreExecute part of the Async task?
No need to do that.. make sure that the method which you want to run in background is called from doInBavkground().. rest you can put in postExecute.... the snippet which you want to run after the backGround task should be in PostExecute(). If You call methods from doInBackground() they still run on background thread.. does't matter where they are.. and if you call it from onPostExecute() then it will run on other thread which ofcourse can make changes in your display.. just like showing dialog etc...
You should always offload as much work as possible to background threads/tasks. Something like database creation should be done in the doInBackground method. The onPreExecute and onPostExecute methods run on the UI thread and are generally used to inform the user of background activity (e.g. using a ProgressDialog).
From experience, I also suggest not using a background service if you can get away with it. If you use one, you should know how to clean it up properly since users generally get annoyed with an application running in the background.