I use ScrollView class in my application. I draw some data on canvas from the compass, these data are periodically updated by user's interaction.
How can I periodically call onDraw method without user's touch on the display? Can I periodically refresh content of the canvas without other thread and calling view.postInvalidate()?
The Handler class is very handy for things like this.
Handler viewHandler = new Handler();
Runnable updateView = new Runnable(){
#Override
public void run(){
globalView.invalidate();
viewHandler.postDelayed(updateView, MILLISECONDS_TILL_UPDATE);
}
};
Call viewHandler.post(updateView); anywhere in the UI thread and it will infinitely call that Runnable every x number of milliseconds specified in MILLISECONDS_TILL_UPDATE. Call viewHandler.removeCallbacks(updateView); to end it or use a boolean flag to prevent another post.
Related
I am trying to draw points to android canvas slowly. I want to use canvas.drawline function however drawing one point to another i want to have small delay. Can you help me please?
Here's the general pattern:
// PSEUDOCODE
// in a class created in a Looper thread, e.g., the main thread
private final Handler handler = new Handler();
static class DrawTask implements Runnable {
// final fields for start point, end point, number of segments, interval, etc.
// mutable field for progress
// constructor with appropriate params
#Override
public void run() {
// draw the current line segment
if(!finished) {
handler.postDelayed(this, interval);
}
}
}
// in some draw method
handler.post(new DrawTask(...));
You might want to hang onto a reference to the DrawTask so you can cancel it with Handler#removeCallbacks(...) in case it's still running when your activity is paused.
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 am basically doing the code post at the bottom of this message.
foobar() posts an event into a common state machine.
I also have touchscreen events posted into the common state machine.
Is it true, that by using a handler I have no synchronization issues?
(i.e., my state machine won't be message up by a touch even and a foobar event) at the same time?
private Handler handler = new Handler();
handler.postDelayed(runnable, 100);
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
foobar();
/* and here comes the "trick" */
handler.postDelayed(this, 100);
}
};
The same instance of Handler object will process through the queue of messages/runnables passed to it on the Looper of choice (main thread by default).
So NO, if you send a list of messages to the Handler they will be run through 1 at a time never in parallel.
BUT if you are concerned about synchronization issues you should synchronize(object) {} your code inside your methods around a common object, that way they will wait for lock on that common object meaning that you could call that method from anywhere and it would never run in parallel with any other code using synchronize(object) {}.
Here's what I'm trying to do first. I'm trying to launch a MapView, which grabs the user's location and loads an overlay with data that changes based upon the user's location.
Code overview:
I have a MapView that grabs the current user's location on creation.
The locationOverlay I'm using calls out a Runnable on first fix:
locationOverlay.runOnFirstFix(centerAroundFix);
This Runnable, centerAroundFix, starts an aSyncTask. As soon as I call the 'new aSyncTask', this error is thrown:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
The asynctask's job is to fetch data, create the overlay, and add the overlay. Creating and executing the asynctask works fine outside of the Runnable.
You have to create the Handler in the UIThread. For example as class member:
public class Activity extends Activity{
private Handler handler = new Handler();
}
Not sure how I didn't see this already...
Can't create handler inside thread which has not called Looper.prepare()
I'm pretty sure this is a duplicate question.
Edit: works. Here's my code. Wrapped the updateLocation() call with "mHandler.post":
private Handler mHandler = new Handler(Looper.getMainLooper());
private Runnable centerAroundFix = new Runnable() {
public void run() {
/* Jump to current location and set zoom accordingly */
map.getController().animateTo(locationOverlay.getMyLocation());
map.getController().setZoom(12);
/* This is a different thread. I need to call this from a thread that has a 'Looper' prepared. */
mHandler.post(new Runnable() {
public void run() {
updateLocation();
}
});
}
};
I have an activity (MapActivity actually) that has a linearLayout with a mapView and a textView, for displaying current speed, among other things. The thing is that I would like the textView to be updated every 0.5 seconds, for example.
I know this can be done with a service (at least that is how I learnt to do it), but I was wondering if it is possible to do so using a Timer inside the MapActivity itself. I tried this approach:
onCreate{
...
updateTimer = new Timer();
updateTimer.scheduleAtFixedRate(doRefresh, 0, updateInterval);
}
private Timer updateTimer;
private TimerTask doRefresh = new TimerTask()
{
public void run()
{
updateData();
}
};
private void updateData()
{
//update the textView with the data
}
private int updateInterval = 500;
However, it gives me the following error:
04-10 22:24:56.529: ERROR/AndroidRuntime(9434): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Then, is it possible to do what I'm trying in an easy way, without using a service class?
Thank you and regards,
=)
Call postDelayed() on some widget, supplying a Runnable and 500 as the delay. The Runnable should do whatever work you want done, then call postDelayed() again with itself as the Runnable and 500 as the delay.
This avoids background threads and services, which are not needed for simple timing events in an activity.