An issue related to handler in android - android

I am using following code to run a timer.
Handler handler = new Handler();
int time=0;
Runnable runable = new Runnable() {
#Override
public void run() {
time++;
Log.d("time", ""+time);
textview.setText(""+time);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runable, 1000);
This handler is attached to UI thread. When I navigate away to some other activity and come back to this activity I get two timers, the old one still persists, I can see this in logcat. Why this is happening ? How to get rid of old timers ?

The reason you have two timers, depends on where your code is in the activity. Activity.onStart and Activity.onResume can (not always) both get called when returning to an activity.
When Activity.onPause, or Activity.onStop is called you can call handler.removeCallbacks(Runnable) to remove your timer runnable.

Related

How to make an image change when clicking on a button

I am displaying image on when clicking on a Button using interface but the image ic_launcher.png does not show up on the Button after some time the image_all.png is only shown.
How should I show my first image for some time using sleep and then show image2?
Should I show both the images on the same button but with time delay.
Any help would be appreciated.
try{
button1.setBackgroundResource(R.drawable.ic_launcher);
Thread.sleep(1000);
} catch(Exception e){
}
button1.setBackgroundResource(R.drawable.images_all);
When you use Thread.sleep(1000); you're actually "stopping" the UI thread, because you're calling sleep(1000); on the UI thread. This causes your application to halt completely for 1 second in your case.
So this isn't such a good idea :-)
Instead you should use something like a Handler for instance. A Handler can be called with a specified delay, so that the action will first be performed after the specified delay. And most importantly, the Handler doesn't "block" the UI thread, as the Thread.sleep(1000); does.
So using a Handler your code, could look something like this instead:
button1.setBackgroundResource(R.drawable.ic_launcher);
Handler uiHandler = new Handler();
uiHandler.postDelayed(new Runnable() {
#Override
public void run() {
button1.setBackgroundResource(R.drawable.images_all);
}
}, 1000);
Notice the 1000 in the end of postDelayed() which tells the Handler to post this "message" after 1000 milliseconds instead of immediately.
On a side-note: It's not good practice to "eat" the Exceptions like you do in your try-catch.
You should be able to see the R.drawable.ic_launcher change occur. My thoughts about this are around how you're doing the Thread.sleep(). Android isn't fond of performing blocking tasks (such as Thread.sleep) in the UI Thread. When you call the setBackgroundResource and then sleep, the thread that would update the UI is sleeping and cannot perform the update. This is how I would do it instead:
button1.setBackgroundResource(R.drawable.ic_launcher);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
button1.setBackgroundResource(R.drawable.images_all);
}
}, 1000);

Check update periodically using postdelayed

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)

Automatically start execution upon activity launch

I'm working on an app that synchronizes some graphic UI events with an audio track. Right now you need to press a button to set everything in motion, after onCreate exits. I'm trying to add functionality to make the audio/graphical interaction start 10 seconds after everything is laid out.
My first thought is, at the end of onCreate, to make the UI thread sleep for 10000 miliseconds using the solution here and then to call button.onClick(). That seems like really bad practice to me, though, and nothing came of trying it anyway. Is there a good way to implement this autostart feature?
Never ever put sleep/delay on UI-thread. Instead, use Handler and its postDelayed method to get it done inside onCreate, onStart or onResume of your Activity. For example:
#Override
protected void onResume() {
super.onResume();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do whatever you want here
}
}, 10000L); //the runnable is executed on UI-thread after 10 seconds of delay
}
Handler handler=new Handler();
Runnable notification = new Runnable()
{
#Override
public void run()
{
//post your code............
}
};
handler.postDelayed(notification,10000);
Yes, putting the UI thread to sleep isnt a good idea.
Try this
private final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
worker.schedule(task, 10, TimeUnit.SECONDS);

Remove callback for handler not work

I have written a handler that calls the method every time interval. I want to remove that handler in on destroy(). The code i use as follows, In Oncreate()
private final Handler _handler = new Handler();
public int DATA_INTERVAL = 30 * 1000;
Runnable getData;
getData = new Runnable()
{
#Override
public void run()
{
recieveData();
}
};
_handler.postDelayed(getData, DATA_INTERVAL);
and in ondestroy(), i use,
_handler.removeCallbacks(getData);
But removecallbacks not work. It calls after exiting the activity.
removeCallbacks(Runnable r):
Remove any pending posts of Runnable r that are in the message queue.
so removeCallbacks(..) only stops pending messages (Runnables) not currently running runnable so if you want to stop currently running Runable then use a Boolean varaible for Stoping Thread when user Exit from your app.
see this post for removeCallbacks not stopping runnable
You are not showing the most important part of the code which is the receiveData method. As you said you are running the task periodically, you must be calling again postDelayed from inside that method to reschedule the task. Probably background threads involved as you cannot do networking on the main thread.
You most likely have a race condition when exiting the Activity. onDestroy runs first and then the task is posted again.
You should use
handler.removeCallbacksAndMessages(null);
Then all handler callbacks will removed.

Why is posting & cancelled a runnable on a View and Handler result in different bahviour?

I've been playing about with Runnables and have discovered that if you postDelayed a Runnable on a View then removing the callback won't work, however if you do the same but post the Runnable on a Handler then removing the callback does work.
Why does this work (Runnable run() code never gets executed):
Runnable runnable = new Runnable() {
#Override
public void run() {
// execute some code
}
};
Handler handler = new Handler();
handler.postDelayed(runnable, 10000);
handler.removeCallbacks(runnable);
where as this doesn't (Runnable run() code always gets executed)?:
Runnable runnable = new Runnable() {
#Override
public void run() {
// execute some code
}
};
View view = findViewById(R.id.some_view);
view.postDelayed(runnable, 10000);
view.removeCallbacks(runnable);
If the View is not attached to a window, I can see this happening, courtesy of what looks like a bug in Android. Tactically, therefore, it may be a question of timing, making sure that you do not post or remove the Runnable until after the View is attached to the window.
If you happen to have a sample project lying around that replicates this problem, I'd like to take a look at it. Otherwise, I will try making my own, so I can have something I can use to report my presumed bug.
UPDATE
As mentioned in the comments, removeCallbacks() on more ordinary widgets works, so it appears this is a WebView-specific problem, per the OP's sample code.
For various reasons, the View's handler (view.getHandler()) may not be ready when you want to initiate the animation.
Therefor you should probably wait before assigning the runnable to the view.
Assuming you are trying to do that from within an Activity, here is a code that waits for the handler to be available before posting the runnable:
private void assignRunnable(final View view, final Runnable runnable, final int delay)
{
if (view.getHandler() == null) {
// View is not ready, postpone assignment
this.getView().postDelayed(new Runnable() {
#Override
public void run() {
assignRunnable(view, runnable, delay);
}
}, 100);
//Abort
return;
}
//View is ready, assign the runnable
view.postDelayed(runnable, delay);
}
Looking at ViewRootImpl.java, the semantics of View.removeCallbacks() seem unclear to say the least.
RunQueue.removeCallbacks just removes the Runnables from an ArrayList. See here.
If RunQueue.executeActions is called before removeCallbacks, then the ArrayList is cleared in all cases making removeCallbacks a no-op. See here.
RunQueue.executeActions is called for every traversal.... See here.
So unless I miss something, View.removeCallbacks will not work if a traversal has happened since you called View.post.
I'll stick to #james-wald comment above and not use View.post

Categories

Resources