I use runOnUIThread method to pass Runnable tasks to the main thread queue, but I need to clear all queue tasks, that I sent before, before sending a new one. How to do it?
use an Handler to post. It has the same effect of runOnUiThread. On your handler instance you can call removeCallbacks(null), which will remove every element in the Handler queue, or removeCallbacks(yourannableinstance) which remove every element of yourannableinstance kind
You can use the removeCallbacks(Runnable r) method. If they are anonymous then you can use removeCallbacksAndMessages(null);. If this doesn't fix the problem please give me more details
The UI thread is also a Looper thread, and it only have one Message Queue.
So if you create a handler in UI thread, and then call handler.post(runnable), the runnable task will store in the message queue.
If you call runOnUIThread(), the run task will also store in the same message queue.
5289 public final void runOnUiThread(Runnable action) {
5290 if (Thread.currentThread() != mUiThread) {
5291 mHandler.post(action); // runOnUiThread also calls handler.post()
5292 } else {
5293 action.run();
5294 }
5295 }
And mHandler.removeCallbacksAndMessages(null) would help you to remove all callbacks and messages.
Related
I've got a background Handler and associated HandlerThread.
val handlerThread = HandlerThread("my background thread").apply { start() }
val handler= Handler(handlerThread)
When exiting the lifecycle of this class, I want to clean up something in the background thread. So I post a runnable to clean it up, and then call handlerThread.quitSafely():
fun onDestroy() {
handler.post {
someObject.release()
}
handlerThread.quitSafely()
}
But I get the LogCat warning "sending message to a Handler on a dead thread", and someObject.release() is never called.
quitSafely() is supposed to stop the thread only after all messages have been processed, but not delayed messages. Looking into the source code, I see that handler.post posts the runnable with a delay of 0, so I guess that means it's not yet in the queue and quitSafely() won't wait for it to post?
What's the correct way to run one more clean-up runnable in the background thread before it's released? Could it be as simple as wrapping handlerThread.quitSafely() in a runnable and posting it to the main handler at the end of the background cleanup runnable?
This is what I ended up doing, and it seems to work fine.
fun onDestroy() {
handler.post {
someObject.release()
handlerThread.quitSafely()
}
}
Please I am blocked with this concept of Handlers and Runnables in Android. Can someone please give me detailed explanation on Handlers and Runnables? Their syntax and implementation? I have read many articles on this but the concepts are not still clear and are even deployed in Java. Thanks in advance
I'm going to try to simplify so bear with me if it is not 100% accurate.
Basically, a Handler is used to communicate with a MessageQueue associated with a Thread.
If you're on the main thread, or if you've called Looper.prepare() in the Thread that you're in, it has a Looper which is basically a holder for the MessageQueue.
This queue is constantly polled so that whenever a Message goes into it, it's dealt with on the Thread associated with this MessageQueue
If you're trying to execute a piece of code on a particular Thread, you have to use a Runnable. It is just an interface that has a void run() method which will be executed by the Looper, on its Thread.
Let's say you're doing a network request, you want it to happen on another Thread but when you get the result you somehow need to pass the data back to the Main Thread in order to update your UI because Views can't be modified from another Thread.
You would do it like so:
// This will let you run method on main thread (even if you're not on main thread)
private final Handler handler = new Handler(Looper.getMainLooper());
// This will let you run method on background thread
private final Executor executor = Executors.newSingleThreadExecutor();
public void doSomething() {
// posting to executor will go to background thread
executor.post(new Runnable() {
#Override
public void run() {
// This will now run on background thread
// you can for example do network request here
// posting to handler will go back to main thread
handler.post(new Runnable() {
#Override
public void run() {
// This will execute on the Main Thread
}
});
}
});
}
I am using Handler in an android project to give a callback to to the main/ui thread.
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
}
mHandler.post(new Runnable() {
public void run() {
freeBeePlaybackEventListener.onError(freeBeeError);
}
});
When I am creating the handler object i.e. mHandler , I am checking whether the handler already exists or not. If not, then I am creating the handler i.e. using a singleton pattern. My question is: Is creation of the handler object thread safe ?
Thanks.
No, this code is not thread safe.
But the problem is not the Handler itself but the creation pattern used.
If the code that you reported here is called at the same time by two different thread, it may happen a critical race where two different Objects (in this case Handler) are created.
If you are sure that this code is called always by the same thread, you can safely use it.
By the way, this is the same problem of the lazy Singleton creation, and it is usually solved in this way:
if( mHandler == null )
{
syncronized( this )
{
if( mHandler == null )
mHandler = new Handler(Looper.getMainLooper());
}
}
Where 'this' is a synchronizing object that may be the class container or anything else.
Handles are Thread Safe.
To handle more complex interactions with a worker thread, you might consider using a Handler in your worker thread, to process messages delivered from the UI thread. (DOC-Worker Threads)
Normally, you create a Handler for a new thread, but you can also create a Handler that's connected to an existing thread. When you connect a Handler to your UI thread, the code that handles messages runs on the UI thread (Android Documetation)
In order to execute some IO operations in my app I wrote a thread, there's nothing on its run method but it has several other methods, like void write(String filename, String data) and void create(String filename), all of which work like a charm. My question is, I used to think this thread was running on the background or something like this but since after removing the .run() statement on my main activity calling said methods still works, how can I have a thread running and waiting for a message from the activity without blocking the app? And second question, since the methods are still working does it mean they are being executed on the main UI thread when I call them from my main activity?
You should use the start() method, instead of the run().
With run() you are running the given Runnable in the calling thread.
With start() you are starting a new thread that handles this Runnable
For the methods to run on the said thread you will have to have to call your methods from the thread and not from any other thread.
class WorkerThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Then use WorkerThread.mHandler.postRunnable or sendMesssage for the work to be done on another thread.
In order to make a que for processing stuff when delivered, you need to make use of android's native stuff which is the best option available:
HandlerThread
Looper
Handler
Message
For examples, read this and this.
I'm having a bit of trouble understanding how to use the Looper prepare()/loop()/quit() logic.
I have three threads: one is the UI thread, one is a game logic thread and the last is a network communication thread (a background thread, lives only while being used).
The game thread has many dependencies on the results of the network calls, so I wanted to spin the network thread off of the game thread and have a Handler post the result back.
Of course, since the UI thread is not involved I need to call Looper.prepare()... somewhere. I thought it should be called in the game thread, but I can't do that because loop() takes it over.
How do I go about posting back to the game thread from network thread with my handler?
What's going on is that once you call Looper.prepare() followed by Looper.loop() on a Thread, all that Thread will ever do is service its MessageQueue until someone calls quit() on its Looper.
The other thing to realize is that, by default, when a Handler is instantiated, it's code will always execute on the Thread it was created on
What you should do is create a new Thread and in run() call Looper.prepare(), setup any Handlers, and then call Looper.loop().
Bearing these things in mind here is the basic pattern I use a lot of places. Also, there's a good chance you should just be using AsyncTask instead.
public class NetworkThread extends Thread {
private Handler mHandler;
private Handler mCallback;
private int QUIT = 0;
private int DOWNLOAD_FILE = 1;
public NetworkThread(Handler onDownloaded) {
mCallback = onDownloaded;
}
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
// things that this thread should do
case QUIT:
Looper.myLooper().quit();
break;
case DOWNLOAD_FILE:
// download the file
mCallback.sendMessage(/*result is ready*/);
}
}
}
Looper.loop();
}
public void stopWorking() {
// construct message to send to mHandler that causes it to call
// Looper.myLooper().quit
}
public void downloadFile(String url) {
// construct a message to send to mHandler that will cause it to
// download the file
}
}
Could you tell some examples for what you are using your network thread? I think you can solve your problems without using Looper.
You can use ASyncTask to perform background task that may update some values in your UI thread. If user has to wait until background operation will be finished, you can show ProgressDialog and block application in OnPreExecute method, and then hide it in onPostExecute.
As I said, please describe more your needs and target which you want to achieve.