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.
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
I have some kotlin code like the following in an android app:
Thread(Runnable {
while (true) {
Thread.sleep(100)
... do useful work ...
if (checkCurrentCondition()) {
... do final useful work ...
return
}
}
}).start()
Here is my question: Is there some way (a callback function or some other mechanism) by which I can know in the main thread, that the background thread above has finished its job?
You may use AsyncTask or ThreadPoolExecutor. AsyncTask has the onPostExecute() method using which you can get the execution result right into UI Thread and do your job after. Also there is Looper/Handler usages for ThreadPoolExecutor to communicate between UI/Worker threads.
For detailed information's look here
If this is in an Activity, you could call runOnUiThread { doWhatever() } from the Thread - it'll hold a reference to the Activity, so don't do this in a long-running thread.
If you create a Handler with Handler(Looper.getMainLooper()) then you can post Runnables to it - basically the same as runOnUiThread except you're not holding onto an Activity, and you can do things like delay and cancel those posted messages.
If you already have some looping activity going on (so you can basically check if the thread's completed) then you could do anything from having a boolean done flag that the thread sets (make it #Volatile so the main thread sees the change) to all the stuff in java.util.concurrent like Futures and the like. Really depends on what you're doing.
Posting a Runnable to the main thread looper is the easiest general way to make a thing happen. But again, if that thread is creating any data in memory that the main thread needs to see, as always you need to handle synchronization, which is its own topic!
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 have a activity with a Listview and a adapter attached to it. I have a class which syncs data and hold it. (I think we should not care about from where data is coming) and it runs on a different thread. Now I want to know the clean way to update adapter but We should not call any function of activity from that class as it runs on different thread.
One way I know is to create handler in activity and pass it to other class and use it from there. But I want to know if activity is in background then activity's function can be called by UI thread or only when activity come in foreground.
I do not want to miss any update and want to update activity when it is in foreground.
If you want to update your listView from another class you can have a few ways to do that.
Send broadcastIntent from your worker class and add BroadcastReceiver to your activity and when you receive the right message, update your listview.
Second way is to create private or public class in your Activity which extends AsyncTask and in your doInBackground() do your work and in onPostExecute(result) update your listview.
Third way which I can imagine, but I don't think it's the best way create a static method is your activity which you can use from any other class for updatiogn your UI.
The best thing which you can use here at least in my opinion is AsyncTask.
this code will do what you want:
runOnUiThread(new Runnable() {
#Override
public void run() {
//your actions
}
});
We should not call any function of activity from that class as it runs on different thread.
That's wrong. (in java an object is not running in a thread. What you can say is that a method is running in the thread from which the method was called)
In Androïd (and in most UI frameworks) the rule is this:
You can only call a method updating UI from the UI thread.
If you have some code running on a thread (not the ui thread) and if that code need to update the UI : you can use the Handler of the UI-thread to post UI update code to the UI-thread. If the activity is not in the foreground when you post something to update it's UI : nevermind! the code you just post will be executed at some point in the future.
You should use AsyncTask, take a look at http://developer.android.com/reference/android/os/AsyncTask.html
Should we start async task from within onHandleIntent() method of IntentService? I read that onHandleIntent() runs in worker thread so will it be safe to start asyncTask from there??
IntentServices already are background-processes; there's no need to start an AsyncTask from there. Also, starting an AsyncTask is 'safe' from anywhere; it's a helper class that helps you multithread. Just make sure you don't manipulate Views in the doInBackground()-method of your AsyncTask if you use it in your Activity.
If you need to spawn multiple threads inside your IntentService, just use:
new Thread(Runnable r).start();
See an example at How to run a Runnable thread in Android?
If you need to call some kind of callback, use Handler. For an example, see http://www.vogella.com/articles/AndroidPerformance/article.html#handler
AsyncTask class is used to provide a mechanism to do achieve multithreading, so your event thread wont get hanged, but as you are using service, you should not use, AsyncTask in the Service, instead you can use, threads, if some long running task is to executed, in the Service.
If you really need to use a AsyncTask inside an IntentService, you can create a method in your AsyncTask that calls de doInBackGround and the onPostExecute. Something like this:
void executeFlowOnBackground(Params params) {
onPostExecute(doInBackground(params));
}
In my case I did this because all App request were made by a class that extended the AsyncTask, and because of the implementation was difficulty to refactor the code.