I was wondering how the TimerTask is working with threads.
For example, I've got a code that executes a TimerTask, which has a 'run' method which will run on the UI Thread.
class looper extends TimerTask {
public looper() {
}
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.schedule(new looper(), new Date(new Date().getTime() + 100));
}
});
}
}
and the timer would start like this:
timer = new Timer();
timer.schedule(new looper(), new Date());
Will the TimerTask create a new thread? if so, how does runOnUiThread will work? will it move the code to the UI thread?
I've tried to eliminate the need to call the TimerTask again (timer.schedule) and just use an infinite loop inside the run to make calculations - but that would block the UI thread and the app will not respond.
P.S - I must have the code run on the UI thread, because it has to update the UI.
So, what's going on here?
About your questions:
runOnUiThread from docs:
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.
The code at TimerTask it is executed on a different thread, so you should call runOnUiThread to execute code.
You are doing it right, but why are you re-creating the timertask at the run method ? Consider using scheduleAtFixedTime , the 100 will be the period and the delay 0.
The run method then will execute the task it is supposed to do.
runOnUiThread(new Runnable() {
#Override
public void run() {
//do whatever
}
});
scheduleAtFixedTime
*Updated:
If its an update to a view it is better to use handler.postDelayed, see an example here it will be executed after a delay on the UI thread.
Related
There are different methods posted on the web on how to run code on the UI thread. They all accomplish the same task, however, I really want to know the difference between these methods.
Method 1:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 2:
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 3:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
In Android, a Thread might have one Looper or MessageQueue. Handler is used to send Message or post Runnable to MessageQueue of a Thread, and it must always be associated with a Looper or a MessageQueue of a Thread.
Method 1
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
When open an app, Android create a new thread (called main thread or UI thread) with a Looper and MessageQueue, this thread is used to render UI and process input events from users.
The above code is create a Handler and associated with Looper of UI thread, so the runnable will be queued to MessageQueue of UI thread, and will be executed later.
Method 2
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Creating a Handler and associated with Looper of current thread, there are 3 cases:
If this code is executed on UI thread, then the runnable will be queued to MessageQueue of UI thread and will be executed later.
If this code is executed on a background thread, if this thread has a Looper, then the runnable will be queued to MessageQueue of background thread and will be executed later.
If this code is executed on a background thread and this thread has no Looper, then an exception will be thrown.
Method 3
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
runOnUiThread is just a utility method of Activity, it used when you want to execute some code on UI thread. The logic behind this method is if current thread is UI thread, then execute it immediately, otherwise used Handler to post a message to MessageQueue of UI thread (like method 1).
Method 1 will always work.
Method 2 will only work if you're already on the UI thread- the new Handler without a Looper parameter creates a Handler to the current thread (and fails if there is no Looper on the current thread).
Method 3 needs to be done in an Activity or called on an Activity object, as runOnUiThread is a function of Activity. But under the hood it will do the same as 1 (although probably keeps a single Handler around to be more efficient, rather than always new-ing one).
All methods works like this:
Method 1 looping handler if loop exist
Method 2 handler can works in all activities if not private or wanted
Method 3 handler can work only in current activity
I'm using Android Studio and emulator android 4.1.2.
My code
Timer timer = new Timer ();
timer.schedule(new TimerTask() {
#Override
public void run() {
myRun();
}
},10000,10000);
result in "unfortunately, app has stopped", however I found out the code
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
myRun();
}
}, 2000);
runs ok and displays as I expect.
What is the inner difference between the two?
P.S.
public void myRun () {
myView.removeAllViews();
drawView = new DrawView(myContext, myView);
myView.addView(drawView);
}
I'm trying to perpetually update a custom view until user cancels it. Just cycle
while (myRun) {
results in emulator becoming unresponsive to even back button, running that update in second thread
new Thread(new Runnable() {
#Override
public void run() {
while (myRun) {
myView.post(new Runnable() {
public void run() {
myView.removeAllViews();
drawView = new DrawView(myContext, myView);
myView.addView(drawView);
}
});
}
}
}).start();
results in same (interestingly to me, if I run debug with breakpoint on while in second thread, screen updates as I expect many times, however running w/out debugging does not update screen).
Timer executes its tasks on a separate thread that is used only for serving tasks created by this particular timer. Handler runs its task on its Looper's thread which may or may not be a UI thread. Generally speaking there's no much difference between this two classes if you use Handler on a separate thread. But it's more common in Android to use Handler and HandlerThread.
If you need to interact with UI, you'd better use Handler.
This is an interesting question and answer lies in Thread/GUI policy that android follows.
As we know, UI runs on main thread. Timer creates a different thread and android does not allow to update UI in a different thread. Why?
Suppose, you have started a thread in your activity that updates a TextView and while the thread is running you move to some other app. Now, main thread no longer exists and when the other thread tries to update the TextView it is not able to find that TextView. As a result, we see a crash.
Now let me come to the difference between TimerTask and Handler.
TimerTask creates a new thread, waits for the time specified and then executes run() method in the same thread. On the other hand, Handler creates a new thread, waits for specified duration then returns to main thread and executes run() method on MAIN thread(if handler is on main thread). Hence, it works fine.
However you can do it with timer too.
See the code below:
final Runnable setRunnable = new Runnable() {
public void run() {
myView.removeAllViews();
drawView = new DrawView(myContext, myView);
myView.addView(drawView);
}
};
TimerTask task = new TimerTask(){
public void run() {
getActivity().runOnUiThread(setRunnable);
}
};
Timer timer = new Timer();
timer.schedule(task, 1000);
In this thread you are setting a runnable to run on UI thread after timer's duration.
OK, so I know how to do a backround task, I know how to do a periodic task (using handle postdelayed and runnable), I also know how to do UI task from background thread (via handler) but I am not able to execute a periodic background task that does some action on the UI thread.
I am trying to execute some background task every minute in which I have to make a network call. After the call is over, depending on the output I have to update the UI. I tried to do something like this
private void DoTask() {
Thread thread = new Thread() {
public void run() {
Looper.prepare();
final Handler handler = new Handler();
handler.post(netRunnable);
Looper.loop();
}
};
thread.start();
}
Runnable netRunnable = new Runnable() {
#Override
public void run() {
handler.getLooper().prepare();
final Handler handler1 = new Handler(Looper.getMainLooper());
if ( do background work and check result){
handler1.post(new Runnable() {
#Override
public void run() {
//Do UI Task
}
});
}
handler.getLooper().loop();
handler.postDelayed(netRunnable, 60000);
}
}
I understand that there might be some fundamental flaws with my implementation but I do not know how to do this task properly. Right now it is giving the error that Only one Looper may be created per thread.I get what it is trying to say. But can anyone please suggest to do this the right way.
You could use Async Tasks. These are designed for it :
http://developer.android.com/reference/android/os/AsyncTask.html
It allows you to execute a network call in the background, then when you get the result, execute an action on the UI thread
Declaration :
private class MyTask extends AsyncTask<Input, Void, Output> {
protected Output doInBackground(Input... inputs) {
// do something on the network
return myOutput;// use this to transmit your result
}
protected void onPostExecute(Output result) {
// do something on UI thread with the result
}
}
If you want to repeat it, just create a runnable to launch it, and after every call, schedule the next one :
MyTask myTask;
Handler handler = new Handler();
Runnable myRunnable = new Runnable() {
#Override
public void run() {
MyTask myTask = new MyTask();
myTask.execute(myArg);
handler.postDelayed(netRunnable, 60000); // schedule next call
}
}
To launch it for the first time :
handler.postDelayed(myRunnable, 60000);
Or, if you want to launch it immediately :
handler.post(myRunnable);
Do not forget to cancel the Task when your activity is destroyed :
myTask.cancel(true);
Maybe you are better of, creating a seperate (Intent)Service and calling it periodically with postDelayed. Create a BroadcastReceiver in your Activity and handle UI changes there.
Another hint for handling UI changes from other threads: It is not possible. Therefore you need to call runOnUiThread. Here is how to use it
If activities are frequently switching, why not reversing the responsibilities. You might create a service which executes a periodic network task.
Then,
- either your activities periodically call this service to get the value.
- or you use a listener system : you create an interface that your activities must implement in order to get notified from the task completion
I've got this code to schedule a task every so often:
final Handler handler = new Handler();
Runnable update = new Runnable() {
#Override
public void run() {
try{
runOnUiThread(new Runnable(){
public void run(){
lbl.setText(info);
cpb.setProgress(Float.valueOf(textInfo);
}
});
handler.postDelayed(this, 1000);
}
catch (Exception e) {
// TODO: handle exception
}
}
};
I want to constantly update the UI (every second, etc). The code works, however, the interface starts lagging. After the code iterates the task a few times the interface stops responding.
Is there any way I can schedule a task to repeat periodically without overloading the memory and without the interface lagging.
Assuming lbl is a TextView and cpb is a ProgressBar, your code will not considerably lag any device as it is. The problem lies somewhere else. Also, you appear to have missed a closing bracket on (Float.valueOf(textInfo);.
As an aside, you are unnecessarily using runOnUiThread inside the Runnable from what I can see. When you create a new Handler() it is implicitly linked to the calling thread's Looper, which I am assuming is the UI thread. In which case, the update Runnable will already be running on the UI thread. EDIT: This should not be the cause of the lag for the record, since iirc runOnUiThread checks if it is being executed on the UI thread then just runs it immediately, without doing another post.
I'm wondering when should I use handler.post(runnable); and when should I use
new Thread(runnable).start();
It is mentioned in developers documentation for Handler:
Causes the Runnable r to be added to the message queue. The runnable
will be run on the thread to which this handler is attached.
Does this mean if I write in the onCreate() of Activity class:
Handler handler = new Handler();
handler.post(runnable);
then runnable will be called in a separate thread or in the Activity's thread?
You should use Handler.post() whenever you want to do operations on the UI thread.
So let's say you want to change a TextView's text in the callback. Because the callback is not running on the UI thread, you should use Handler.post().
In Android, as in many other UI frameworks, UI elements (widgets) can be only modified from UI thread.
Also note that the terms "UI thread" and "main thread" are often used interchangeably.
Edit: an example of the long-running task:
mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// You may want to update a progress
// bar every second, so use a handler:
mHandler.post(new Runnable() {
#Override
public void run () {
// make operation on the UI - for example
// on a progress bar.
}
});
}
}).start();
Of course, if the task you want to perform is really long and there is a risk that user might switch to some another app in the meantime, you should consider using a Service.
To answer you specific question:
Does this mean if in the onCreate of Activity class I write:
Handler handler = new Handler() hanlder.post(runnable); then, runnable
will be called in a separate thread or on the Activity's thread?
No it won't be. The Runnable will be called on the Main Thread itself.
Handler is simply used for posting a message to the thread to which it is attached (where its is created).
It does not create a thread on its own.
In your example, you created a Handler in the main Thread (that where Activity.OnCreate() is called) and hence any message posted on such a Handler will be run on the Main Thread only.
Example is jacked:
mHandler = new Handler();
new Thread(new Runnable(){
#Override
public void run () {
mHandler.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
Alternatively you can skip the handler and use the post method on the view directly:
new Thread(new Runnable(){
#Override
public void run () {
mUiView.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
This is a good post that outlines the difference: What exactly does the post method do?
use handler.post() when you want to post the code (usually from background thread) to the main thread. Yea, POST,just like you, post a letter to someone. With the help of handler the code will be executed ASAP i.e. almost immediately.