I am using HandlerThreaqd to handle blocks of code that needs a lot of time to run:
HandlerThread t = new .....
Handler h = new Handler(t.getLooper());
while(true)
{
h.post(new Runnable(){ public void run() { /* code that needs a lot of time */ } });
}
It is clear that after a period of time there will be pending runnables in the message queue of the thread, so is it possible to cancel these runnables? has somebody tried to do it?
you can cancel a thread by this code:
h.removeCallbacks("name of your Runnable Obj");
Related
I was trying to understand the looper and handler in android, but got stuck with the example written.
What I am trying to do is, add a looper to the thread, to make thread running continuously in run() method. Then post messages or runnables to the hanlder thread.
public class HLClass extends Thread {
Handler mHandler;
#Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HLClass","In Handler, Msg = "+msg.arg1);
}
};
Looper.loop();
}
}
This is how I am trying to call handler:
HLClass hlc = new HLClass();
hlc.start();
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
Error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Message android.os.Handler.obtainMessage()' on a null object reference
Here, what really I am trying to understand that, how I can attach a handler to thread and then post message from any other thread
How can I safely post Message or Runnable to handler without error.
You can try following code for sending message.
final HLClass hlc = new HLClass();
hlc.start();
new Handler().postDelayed(new Runnable() {
public void run() {
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
}
}, 300);
A Handler is a component that can be attached to a thread and then made to perform some action on that thread via simple messages or Runnable tasks. It works in conjunction with another component, Looper, which is in charge of message processing in a particular thread.
When a Handler is created, it can get a Looper object in the constructor, which indicates which thread the handler is attached to. If you want to use a handler attached to the main thread, you need to use the looper associated with the main thread by calling Looper.getMainLooper().
In this case, to update the UI from a background thread, you can create a handler attached to the UI thread, and then post an action as a Runnable:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// update the ui from here
}
});
This approach is a lot better than the first one, but there is an even simpler way to do this…
final Handler handler = new Handler();
LOG.d("delay");
handler.postDelayed(new Runnable() {
#Override public void run() {
LOG.d("notify!");
//calling some methods here
}
}, 2000);
The "delay" does shows in the log, but not others at all. And the method called in the run() is not called at all also. Can anyone help explain why this happens, am I doing anything wrong?
The class that has this code extends IntentService, will this be a problem?
============================
UPDATE:
I put this code in the class that extends IntentService. The only place I found it worked was in the constructor. But I need to put it in the onHandleIntent method. So I checked the documentation for onHandleIntent and it said:
This method is invoked on the worker thread with a request to process.Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf.
So based on the result I get, I feel like I cannot use postDelayed in "worker thread". But can anyone explain this a bit more, like why this is not working in worker thread? Thanks in advance.
Convert
final Handler handler = new Handler();
to
final Handler handler = new Handler(Looper.getMainLooper());
This worked for me.
You are using looper of the main thread. You must create a new looper and then give it to your handler.
HandlerThread handlerThread = new HandlerThread("background-thread");
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper());
handler.postDelayed(new Runnable() {
#Override public void run() {
LOG.d("notify!");
// call some methods here
// make sure to finish the thread to avoid leaking memory
handlerThread.quitSafely();
}
}, 2000);
Or you can use Thread.sleep(long millis).
try {
Thread.sleep(2000);
// call some methods here
} catch (InterruptedException e) {
e.printStackTrace();
}
If you want to stop a sleeping thread, use yourThread.interrupt();
this is how i use handler:
import android.os.Handler;
Handler handler;
//initialize handler
handler = new Handler();
//to start handler
handler.post(runnableName);
private Runnable runnableName= new Runnable() {
#Override
public void run() {
//call function, do something
handler.postDelayed(runnableName, delay);//this is the line that makes a runnable repeat itself
}
};
Handlers and Services will be predictable when the device screen is on.
If the devices goes to sleep for example the Handler will not be a viable solution.
A much more better and reliable solution will be to use:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
IntentService is not designed for such scenario. You can use a regular Service instead. You can put the handler inside the onStartCommand(). Don't forget to
call stopSelf() on the Service instance to shut it down after the handler.postDelayed(){}
The most simple is to wait before ending onHandleIntent():
SystemClock.sleep(2000);
In my app (as long as it is open) I want to sync my data with my server.
My strategy is the following :
//create the handler on which we will use postdelayed
Handler handler = new Handler();
//create the first runnable.
//Will this run on UI thread at this stage ? as it is being called from the handler ?
Runnable runnable1 = new Runnable()
{
public void run()
{
Thread t = new Thread(runnable2);
}
};
//create the second runnable.
//This is for sure being called from a thread, so it will not run on UI thread ? NO ?
Runnable runnable2 = new Runnable()
{
public void run()
{
//connect to internet
//make the check periodical
handler.postdelayed(runnable1, 1000);
}
};
//call the postdelayed.
handler.postdelayed(runnable1, 1000);
In case I want the handler to stop its runnable task once the application is closed. What shall I do incase I have several activities and I do not know where is the user when he/clicks the home button. Should I include a check in all onDestroys() ?
Yes you're second Runnable will be ran on a new thread not the UI thread.
When you do new Handler(); this creates a handle to the current thread, if this code was in onCreate that thread would be the UI thread.
Therefore when you do handler.post it will post onto the UI thread (runnable1) , but when you start runnable2 you are explicitly creating a new thread to run this on.
It might not be the right strategy to create a new thread every 1 second (postDelayed ..1000) perhaps keep a reference to another background thread and post it a message every second to do something new.
To stop your repeated runnables you need to call removeCallbacks(runnable1) in onPause of any Activity (that I assume called postDelayed in onCreate)
I have a thread where I need to periodically perform some checks, get files from the web, and send messages to the main UI thread. I even need to use UI thread parameters (like the map visible area) on each loop of the worker thread. So I suppose that i need to implement bidirectional communication between UIthread and workerThread.
Another problem is that I need to save the identifier of each marker added to the map. I want to save the result of map.addMarker inside my custom array stored in my worker thread. this means that from the uithread, where i update the map, i should tell the workerThread to update the array of markers..
This is a sample of my actual worker thread:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
My actual problem is that when the UI thread ends processing the message received from the worker thread i should perform an action on the worker thread.
I thought 2 solutions:
1)wait on the worker thread till the message has been processed by the UI thread
2)process the message on the UI thread and then send a message to the worker thread.
I don't know how to do the solution1, so i tried the solution2. I tried adding a looper to my worker thread (RUN sub), this way:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// Act on the message received from my UI thread doing my stuff
}
};
Looper.loop();
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
The problem is that after the Looper.loop() no line of code is executed. I read that this is normal. I read many articles but I didn't understand how should I allow the execution of my while loop, and simultaneously process messages coming from my UI thread.
I hope the problem is clear. Suggest me the best solution.
don't do this:
while(true){
sleep(2000);
it's awfully bad on so many levels. if you need some background processing, use AsyncTasks, if you need a repeating event, use:
private Handler mHandler = new Handler();
private Runnable mSomeTask = new Runnable() {
public void run() {
doSomething();
}
};
and then somewhere in the code:
mHandler.postDelayed(mSomeTask, 100);
this will make your program work faster, jam less resources and basically be a better Android citizen.
I realize this is a very old question, but for periodic task scheduling, use this code:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> periodicTask = scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// do some magic stuff here
// note however, that you're running in background!
Log.d("PeriodicTask", "Doing something....");
}
}, 0 /* initial delay */, 10 /* start every 10 seconds */, TimeUnit.SECONDS);
and when you need to stop the periodic task, just issue
periodicTask.cancel(true);
I am using the following code to access a url:
final Handler handler = new Handler();
Runnable runnable = new Runnable()
{
public void run()
{
img.setImageBitmap(returnBitmap("fromurl"));
handler.postDelayed(this, 50);
}
};
handler.postDelayed(runnable, 2000);
I observed that if the server is not up the app takes ages to close correctly if I hit the back button. Is there anyway way I could speed up the exit procedure.
Runnables will exit automatically when finished with their run() method. If you are employing a loop to do some work, the solution that Jay Ho suggested will help exit from the loop cleanly. If you want to prevent the Handler from executing the runnable (before it posts) you can use handler.removeCallbacksAndMessages(null)1 to clear the queue. Placing it in onDestroy() is your best bet. Otherwise, you're on your own. Once you've spawned a thread, you're at the mercy of the Android operating system to terminate it once its done.
Side note: I've run into problems like this before, and it's usually a call to a system service or the implementation of a Broadcast Listener or Alarm that mucks up the exit process.
private Runnable runnable = new Runnable() {
private boolean killMe=false;
public void run() {
//some work
if(!killMe) {
img.setImageBitmap(returnBitmap("fromurl"));
handler.postDelayed(this, 50);
}
}
public void kill(){
killMe=true;
}
};
ThreadPoolExecutor threadPoolExecutor = Executors.newSingleThreadExecutor();
Runnable longRunningTask = new Runnable();
// submit task to threadpool:
Future longRunningTaskFurure = threadPoolExecutor.submit(longRunningTask);
... ...
// At some point in the future, if you want to kill the task:
longRunningTaskFuture.cancel(true);
... ...