Updating the GUI from a TimerTask using Handler - java

Globally, I have a the following:
Timer timer = new Timer();
in my onResume() I have the following code.
timer.schedule(new syncTimerTask(), 1, 30000);
and my syncTimerTask is as follows :
class syncOutgoingUpdatesTimerTask extends TimerTask
{
public void run()
{
//some sync process with outer back end server
//fetch results etc
myHandler.post(myRunnable);
}
}
my handler and runnable are declared globally as follows
final Handler myHandler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
//update GUI, text views whatever.
}
};
And inside my onPause() I call timer.cancel();
The above code is neat, straight to the point and does the job perfectly.
But in order to grasp the idea better, I have some concerns and questions.
Assume the syncing too a lot of time, and the user pressed the back button. This will cause the onPause to get caused , which will stop the timer from repeating itself, however the running TimerTask will continue running. But what happens when the code reaches the line of myHandler.post(myRunnable); where the handler calls the runnable, but there is no GUI to update ? Do I get a null pointer there ?
Assume the sync started and again it took a lot of time, in which state, the user pressed the home button and got out of the app and removed the app from the 'recent apps' which 'kills' the app, calling onDestroy() on all methods. In this case, does the thread of the timer (which is a seperate thread and not the UI thread, stops wherever it is, (even though it might be in the middle) because it is associated with the app ?), assume this is true, the code won't even reach the myHandler.post(myRunnable); so no null pointers will occur.. is this the case ?

Yes, the event will run, and if you nullify things out it might cause problems. The best you can do is to have a flag that tells you, from your Runnable, that the activity is paused.
No, the app is not killed, just stopped (unless the Android process manager kills it for memory as usual). In this case your timer thread continues running and executes the Runnable in the main thread, with the same potential problems of 1.

Related

JAVA .wait() for waiting before runing a method android studio

So, I am working in android studio and trying to set a pause between two methods. In the first one, a gif is loaded and in the second one a pop-up message appears. I've tried to use Thread.sleep and the TimeUnit as bellow but both of them execute in a way that the time is waited before running everything else. In another words, my code down bellow waits 4 seconds and then runs gameGif() and gameFinish() simultaneously. Here is my piece of code:
gameGif();
{
try
{
TimeUnit.SECONDS.sleep(4);
}
catch(InterruptedException ex)
{}
}
gameFinish();
This is working for me
gameGif();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
gameFinish();
}
}, 4000);
What you are doing is setting the intention to update the UI. The actual UI updates are performed by the Android Looper separate to your code. In fact, by calling wait(), you're actually blocking the rendering thread from doing its update.
Using a Handler is the correct way to do it, as Matus posts. The Handler will organise the scheduling with the Looper and will still allow the Looper to run (i.e. is non-blocking). When the timeout elapses it will call the Runnable
The one thing you need to be careful with this approach, is to call the Handler on the UI loop (i.e. from one of the 'normal' Android methods). If you call it from your own Thread it won't interact with the Looper correctly.

repetitve timer doesnt work when looper is inside the runnable

I am testing a few things with TimerTask and Timers and android , and i noticed that if i put Looper inside the run () method, the TimerTask runs just once, even though i defined it to be repetitive.Any ideas why is that ?
here is the MainActivity part
Timer timi=new Timer();
timi.scheduleAtFixedRate(new locac(nok,this),10, 1000);
and here is the worker timerTask class
public void run ()
{
Looper.prepare();
int loto=23;
int lato=23;
long time=1220227200;
String test=String.valueOf(lato);
String test3=String.valueOf(loto);
String test1=String.valueOf(time);
dbadapter mkola=new dbadapter(Ctx);
mkola.openToWrite();
mkola.insert(test,test1,test3);
Looper.loop();
}
as soon as i remove the Looper , it works nice.
i need the Looper because at a point i want to invoke some methods inside which initiate a Handler
thanks in advance
It is because your TimrTask never returns (because of the call to Looper.loop() )
Form The Timertask documentation, emphasis mine (Oracle Documentation, Android's is not that clear) http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
:
Corresponding to each Timer object is a single background thread that
is used to execute all of the timer's tasks, sequentially. Timer tasks
should complete quickly. If a timer task takes excessive time to
complete, it "hogs" the timer's task execution thread. This can, in
turn, delay the execution of subsequent tasks, which may "bunch up"
and execute in rapid succession when (and if) the offending task
finally completes.
So what happens is that your TimerTask is run in the single thread of your Timer and as it's run method never returns it bloks the thread, which cannot run the new scheduled itereation of your TimerTask anymore.

Main thread: can runnables be preempted?

I've a runnable instance that self-schedules itself again at the end of its run method:
private class MyRunnable implements Runnable {
private volatile boolean cancelled = false;
private Handler handler;
public MyRunnable(Handler h){
handler = h;
}
#Override
public void run(){
//Do stuff
if(!cancelled){
//Preemtion possible here?
handler.postDelayed(this, 1000);
}
}
public void selfStart(){
cancelled = false;
handler.removeCallbacks(this);
handler.post(this);
}
public void selfCancel(){
cancelled = true;
handler.removeCallbacks(this);
}
}
The runnable is first scheduled in the main thread calling selfStart from an activity's onStart.
At the same time, the runnable can be externally cancelled (calling selfCancel) from the activity's onStop and also from a Broadcast Receiver.
AFAIK Runnable.run, Activity.onStop and BroadcastReceiver.onReceive run in the same thread (the main one), so at first glance I thought there would be no thread-safety issues.
But it looks like sometimes, the runnable is being preemted in the middle of its run call, then it is cancelled from the activity or receiver, and then it resumes and re-schedules itself again.
Is this possible?
UPDATE:
I'll try to explain better the issue. The class shown above is intended to run tasks periodically in the main thread. In the "do stuff" comment there's actually code that updates a TextView with a value passed to the MyRunnable constructor. The activity cancels the current runnable and starts a new one when certain intents are received. Despite the current runnable is always requested to cancel itself before the new one is created, sometimes it is being left running along with the new one, so the text view is showing alternating values. This is not the intended behavior.
I thought if the runnable was currently running in the main thread, it would run until completion, and then other runnables or event handlers would be taken out of the queue and executed if needed, but no pending event or runnable could be "half executed".
There are two kinds of tasks running in the main thread that are related to the problem:
R1: The MyRunnable self-scheduling task. Runs and then it self-posts itself again with a delay of 1s.
R2: The event handlers that request cancellation of the current MyRunnable instance and create a new R1'. These happen randomly and are executed only once.
I've contemplated two scenarios. The first one:
R1 is already running in the main thread.
R2 arrives and is enqueued in the main thread.
R1 finishes running and posts itself again.
R2 runs and removes callbacks for R1.
R1 should never run again.
And the second one:
R1 is not running but is scheduled.
R2 arrives and removes callbacks for R1.
R1 should never run again.
Theoretically, if there's no preemtion, and there's only a single thread, how comes sometimes there are two R1s in the main thread?
As you have no synchronization on selfStart or selfCancel this is entirely possible.
An unreleated note, selfCancel could be called on a separate thread after your if statement in your run method has checked the value of cancelled. MyRunnable would then get one more call to run, which would end immediately as it's been cancelled.
My suggestion would be to move the //Do stuff inside the canceled check.
This avoids the race regardless of assumptions about which thread things are running on.
#Override
public void run(){
if(!cancelled){
//Do stuff
handler.post(this);
}
}
In general for maintainability, try to write code that works correctly regardless of the thread it is being run on. You never know when somebody will call selfCancel() on some other thread later thinking it is okay, when you have assumed they won't do that.
Well as others have said, there's no way a runnable can be preempted in a single thread. I also thought this idea was absurd. Shame on me for coming up with that nonsense.
There was nothing wrong with the runnables themselves. They were launched in the activity's onStart, and cancelled from Intents received by the activity, or in the activity's onStop. An this is the root of the problem: assuming onStart and onStop would run in a predictable order. Sometimes when coming back to the activity, a second onStart was executed before the first activity's onStop. Two tasks were running and the thing messed up to a point where the first task was never terminated.
Ensuring no task is launched without previous termination of the current one solved the issue.

How do you wait for a thread to finish in Java without freezing the GUI?

I am coding an android game in Eclipse with java. The main goal is to wait for a thread to finish, then to set a boolean to true. The reason is that when a user clicks a button it will only run if the boolean is true. However, when I call a method, it creates a thread and does its thing, then when it is done, it sets the boolean to true. However, it automatically sets the boolean to true while the thread is still running, and so the user can click the button (which messes some things up). Is there a way to wait for a thread to finish without freezing the screen? (thread.join() seems to be freezing it)
Any help is appreciated.
Seems like you don't really need to wait until the thread is done to continue, the way I see it you only need to be notified once it's done, the simplest approach for it would be passing a "callback listener" object to the thread, and execute it when done, this will let you know that you are ready to continue, OR a better approacch would be an AsyncTask which will allow you to do everything in background and when done you can use the onPostExecute method, hope this helps.
This is the way you create and add a callback to be notified when your thread has completed:
//Create your callback listener interface...
public interface MyThreadListener{
public void threadFinished();
}
//This is the method that runs some functionality in a separate thread
public void executeTaskInSeparateThread(final MyThreadListener listener){
new Thread(new Runnable() {
#Override
public void run() {
// DO your long task here...
//Notify when done before leaving run method...
listener.threadFinished();
}
}).start();
}
//Use it like this
//Create the implementation of the listener you want (this is something like what you usually do for buttons or any other android listener)
MyThreadListener listener = new MyThreadListener() {
#Override
public void threadFinished() {
//Do whatever you want when notified...
//NOTE: This method will be called on a separated thread too, you cannot modify views...
}
};
executeTaskInSeparateThread(listener);
Once the thread completed it will execute the listener and will let you know is done...
Regards!
Q: Why not set the button to "disabled" when you start the thread (btn=.setEnabled(false);), then have the thread set the button to "enabled" just before it exits?
And yes, calling "thread.join()" (or ANY blocking call) from your UI thread will indeed "freeze" it :)
PS:
Are you using a Java thread, or an Android "Asynch Task"? Here's an excellent tutorial on the latter:
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
Use an AsyncTask. In onPreExecute() disable your button so the user cannot click it again.
In onPostExecute method enable the button again. Do the time consuming logic in the doInBackground method.
try to create a Task extends AsyncTask, override the doinBackground mothed,Then put "time-consuming operation" in it. When your task done,it'll goto "onPostExecute",just use an Interface call back to the Actiity and enable the Button . When you use the AsyncTask you should know that: The Default AsyncTask has got a "pool",System allow 5 instace of AsyncTask ,if you got more than 5 Task,you should create a no limit pool.
My English is so so bad,lol.

How to make service for working by timer?

I have following task: to make service which executes and gets data from Internet every 10 minutes. I try to use combination Service + Timer, but in this case I can't control service (I executes TimerTask with delay in onCreate() method of service, and when I interrupt service TimerTask won't stopped). I need 2 buttons only: "start service" and "stop service". What is the best way in this case? Thank you for helping.
You should use the AlarmManager. See this question Android: How to use AlarmManager for help on that. There is no need to waste a users memory by keeping your service alive doing nothing for 10 minutes. Also, if the phone is asleep, your timer will not run. By using the AlarmManager, the phone will automatically be woken up every 10 minutes and your service can be called to perform its internet download task.
If I understand you well, you want to know how to stop a TimerTask when you interrupt your Service?!
If so, read on, otherwise please explain better.
To stop a TimerTask from executing again (assuming it was scheduled to run repeatedly) you must call the cancel() method. The preferred method is to let the TimerTask itself call the cancel() method after checking some boolean flag which can be set externally.
For example:
class MyTimerTask extends TimerTask() {
private boolean alive = true;
public void run() {
if (alive) {
// do something
} else {
cancel();
}
}
public void stop() {
alive = false;
}
}
Then, it's pretty obvious that when you interrupt your service, you just have to call MyTimerTask.stop().

Categories