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!
Related
I am a beginner in android application development.I am working with threads in android.I have read about a runOnUiThread which run code on main UI(if i am not wrong?i guess.).
My question is what is the difference between normal code on main UI and code inside runOnIUThread.
Example:1
class A
{
getDataFromServer(foo);//Code on mainUI
}
Example:2
getActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
getDataFromServer(foo);
}
});
What is difference in both example.Please help me.Your response will be a new learning for me.
Assuming that you meant simple code for UIThread code,
What is a thread ?
A thread defines a process running
First runOnUiThread ..
Runs the specified action on the UI thread. If the current thread is
the UI thread, then the action is executed immediately. If the current
thread is not the UI thread, the action is posted to the event queue
of the UI thread.
What is UIThread
Main thread of execution for your application
Most of your application code will run here onCreate, onPause, onDestroy, onClick, etc.
So simply Anything that causes the UI to be updated or changed HAS to happen on the UI thread
When you explicitly spawn a new thread to do work in the background, this code is not run on the UIThread.Now what if you want to do something that changes the UI?
Then you are welcome to runOnUiThread
You have to use runOnUiThread() when you want to update your UI from a Non-UI Thread. For eg- If you want to update your UI from a background Thread. You can also use Handler for the same thing.
Normally your code is executed on your UI thread. For longer taking tasks (such as network requests, etc...) you will use a background tasks (Handler, AsyncTask, Thread, ...).
As your Views can only be touched from a UI thread, you use runOnUiThread() if you are executing code in a background thread and you need to update your views, from this background thread.
To explain 'why' Android has the 'runOnUiThread()' option, it is important to understand that java is only used to create the bytecode (dex) that Android uses. The code running on the phone is NOT java.
Additionally, Android threads 'can' have a thing called a 'looper'. This 'looper' is what handles 'tasks(technically runnables and messages)' in order via a queue. The 'main ui thread' has by default a looper already attached to it.
That means that your runnable you created was put onto the looper's queue of the main UI thread. (this is why the runnable is NOT instantaneously ran, but will be ran 'quickly'/'soon')
The reason you'd use a runnable to run code on the UI thread is because you are in some other 'background thread' that you created... and want to update the UI in some way. (Only the UI thread can interact with the UI)
I have a bunch of AsyncTasks and their callbacks (listener interfaces) that I dont want to have anything to do with the UI thread.
Reading the answer here: Android : can AsyncTask return in another thread than UI thread?
I am left with the impressin that I can only start AsyncTasks from the UI Thread which means the callbacks that I invoke from their onPostExecute methods will also be in the main thread.
How do I move all this logic away from the UI thread?
First, based on some issues I've had before when trying to run AsyncTasks in an IntentService, I think your assumption that you cannot run an AsyncTask from a non-UI thread is false.
The problem I've found with starting AsyncTasks off the UI thread is not that they don't run or that they cause crashes, but that onPostExecute() doesn't automatically run on the main UI thread after the other stuff finishes. I wouldn't recommend doing it, but you probably could if you wanted to.
But the whole reason AsyncTasks exist are basically to have an easy way to run some code off the UI thread and then be able to alter UI stuff after it's finished. So if you don't want to do anything at all with the UI thread, you shouldn't need to use an AsyncTask at all. If you don't need to run any code on the UI thread, you can just use something like:
new Thread(new Runnable() {
public void run() {
//Do your stuff
}
}).start();
So, there are multiple similar questions/answers about how to do a delay on Android. However they mostly focus on doing this on UI thread.
What if I need a delay in a worker thread in a service (and I don't want to put the thread to sleep)? the Handler.postDelayed() doesn't work as there is a "can't create a handler inside thread has not called Looper.prepare()" exception. CountDownTimer doesn't work for the same reason. And I don't have any views to call runOnUiThread().
So is the only solution to have a looper on each thread I have or there is another way to do this?
UPDATE:
It's silly, but I found the answer working for me in my own old code :).
Basically, if you want to start a Runnable with a delay from a non-UI thread, all you need to do is ask the main looper to handle this.
Handler handler = new Handler(Looper.getMainLooper());
Runnable r = new Runnable() {
#Override
public void run() {
// Do stuff to be run after a delay
// CAUTION: this won't be run on the same thread
}
};
handler.postDelayed(r, DELAY_TIME);
The drawback could be that the code in that Runnable will not be run on the same thread as the original code. This is why I'm not putting this approach as an answer to be accepted (I admit, the original question sounded like I want a timed event to happen on the same non-UI thread. For this I don't have an answer yet except the one from Emmanuel that I must attach a Looper to my thread). For my purposes however this works as I only need to start a service upon timeout.
Like you have seen from the Exceptions in order to use Handlers in a Thread you need to attach the Thread to the Looper. To give a bit more context, when you call postDelay() you are posting a message to the Thread's MessageQueue; the Looper is responsible for managing this Queue. So if you want to go the Handler route you will need to set up the Thread with a Looper.
If you want to delay the Thread without making it sleep() (I do not know why you cannot use sleep()) you can have a while that runs until a certain time from now has elapsed. (This sounds like a horrible idea).
Can anyone tell me if there's any difference between using runOnUiThread() versus Looper.getMainLooper().post() to execute a task on the UI thread in Android??
The only thing I can determine is that since runOnUiThread is a non-static Activity method, Looper.getMainLooper().post() is more convenient when you need to code something in a class that can't see the Activity (such as an interface).
I'm not looking for a discussion on WHETHER something should be executed on the UI thread, I get that some things can't and a great many things shouldn't, however, some things (like starting up an AsyncTask) MUST be executed from the UI thread.
The following behaves the same when called from background threads:
using Looper.getMainLooper()
Runnable task = getTask();
new Handler(Looper.getMainLooper()).post(task);
using Activity#runOnUiThread()
Runnable task = getTask();
runOnUiThread(task);
The only difference is when you do that from the UI thread since
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
will check if the current Thread is already the UI thread and then execute it directly. Posting it as a message will delay the execution until you return from the current UI-thread method.
There is also a third way to execute a Runnable on the UI thread which would be View#post(Runnable) - this one will always post the message even when called from the UI thread. That is useful since that will ensure that the View has been properly constructed and has a layout before the code is executed.
When I need something to run asynchronously, such as a long running task or a logic that uses the network, or for whatever reason,
Starting a new Thread and running it works fine.
Creating a Handler and running it works as well.
What's the difference? When should I use each one?
What are the advantages / reasons to use a Handler and not a Thread?
PS.
- For this question's sake, let's ignore AsyncTask.
- Handler().postDelayed use case is clear to me, for this question's sake let's assume I need the task to start immediately.
If whatever you are doing is "heavy" you should be doing it in a Thread. If you do not explicitly start it in its own thread, then it will run on the main (UI) thread which may be noticeable as jittery or slow to respond interface by your users.
Interestingly when you are using a thread it is often useful to also use a Handler as a means of communication between the work thread that you are starting and the main thread.
A typical Thread/Handler interaction might look something like this:
Handler h = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 0){
updateUI();
}else{
showErrorDialog();
}
}
};
Thread t = new Thread() {
#Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler and it will do it for us.
h.sendEmptyMessage(0);
}else{
h.sendEmptyMessage(1);
}
}
};
In general though, the take home is that you should use a Thread any time you are doing some work that could be long running or very intensive (i.e. anything network, file IO, heavy arithmatic, etc).
Handler and Thread are really 2 different things.
A thread must be created to execute long running jobs.
A Handler is very convenient object to communicate between 2 threads (for instance : a background thread need to update the UI. You can use a Handler to post some Runnable from your background thread to the UI thread).
So you don't have the choice between Handler or Thread. Use a thread to do heavy jobs! (you can use a Handler if your background thread will trigger some job to be done in another thread - most of the time the UI thread)
Handler and Thread are two different things, but they do not contradict each other. You can have a Handler and a Thread at the same time and actually each Handler must be running in a Thread.
For more details, you may want to check out this article.
A Handler runs on the same Thread, a Thread runs on a different thread.
Use a Handler if you need to run something on the same thread, usually a GUI element or something like that.
Use a Thread if you want to keep the main thread free to do other things. Use this for anything that takes a significant amount of time.
Handlers are the best way of communication between the background and UI thread. Generally Handlers are associated with message Queue of a Thread and they are used to send messages and runnable to the Message.
USE:
Thread: To do tasks in saperate(Background) thread than UI thread. (helps to unblock the UI thread)
Handler Used to communicate between the UI and Background thread.
Have a look at this article
If you need to update the user interface from a new Thread, you need
to synchronize with the user interface thread.
You can use the android.os.Handler class or the AsyncTasks class for
this.
The Handler class can update the user interface. A Handler provides
methods for receiving instances of the Message or Runnable class.
You thread can post messages via the sendMessage(Message msg) method
or via the sendEmptyMessage() method.
... more info here about threads etc. (includes turorials for the different threading and sync mechanisms and when to use what)
What are the advantages / reasons to use a Handler and not a Thread?
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue.
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler:
To schedule messages and Runnables to be executed as some point in the future
To enqueue an action to be performed on a different thread than your own.
If you use java threads, you have to handle somethings on your own - synchronizing with main thread, cancelling a thread etc.
This single Thread does not create a thread pool unless you use ThreadPoolExecutor or ExecutorService API.
(Taken this query from your comments on Blackbelt answer)
Why not use an Executor? and even if I did want to use a Handler to do that, how?
Reference : Thread Performance article
There are certain types of work that can be reduced to highly parallel, distributed tasks. With the sheer volume of work packets this creates, AsyncTask and HandlerThread aren’t appropriate classes. The single-threaded nature of AsyncTask would turn all the threadpooled work into a linear system. Using the HandlerThread class, on the other hand, would require the programmer to manually manage load balancing between a group of threads.
ThreadPoolExecutor is a helper class to make this process easier. This class manages the creation of a group of threads, sets their priorities, and manages how work is distributed among those threads. As workload increases or decreases, the class spins up or destroys more threads to adjust to the workload.
BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
ThreadPoolExecutor executor = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(), // Initial pool size
Runtime.getRuntime().availableProcessors(), // Max pool size
1, // KEEP_ALIVE_TIME
TimeUnit.SECONDS, // KEEP_ALIVE_TIME_UNIT
workQueue);
You can refer to this developer guide article on create-threadpool for more details.
Have a look at this post for usage of Handler to run multiple Runnable instances. In this case, all Runnable tasks will run in a single Thread.
Android: Toast in a thread
Handler can be used in conjunction with Thread in order to create a Queued mechanism. Uou can use the handler to post something on the Thread Looper
If you have to execute a task only once separately outside main thread, then use Thread. If you want to execute tasks repeatedly then android provides a way to keep threads alive and receive the messages or Runnable objects to process them using Looper in a MessageQueue.