I'm running a handler inside of a while loop, against a lat/lng span so if i'm outside of a certain span, that map will automatically zoomIn. I'm using this exact same setup, comparing zoom levels instead of spans and it works just fine. Here's what I'm doing...
public static void smoothZoomToSpan(final MapController controller,
MapView v, GeoPoint center, int latitudeSpan, int longitudeSpan) {
final Handler handler = new Handler();
final MapView mapView = v;
final int currentLatitudeSpan = v.getLatitudeSpan();
final int currentLongitudeSpan = v.getLongitudeSpan();
final int targetLatitudeSpan = latitudeSpan;
final int targetLongitudeSpan = longitudeSpan;
controller.animateTo(center, new Runnable() {
public void run() {
int curLatSpan = currentLatitudeSpan;
int curLngSpan = currentLongitudeSpan;
int tarLatSpn = targetLatitudeSpan;
int tarLngSpan = targetLongitudeSpan;
long delay = 0;
while ((curLatSpan - 6000 > tarLatSpn)
|| (curLngSpan - 6000 > tarLngSpan)) {
Log.e("ZoomIn", "Thinks we should!");
handler.postDelayed(new Runnable() {
#Override
public void run() {
controller.zoomIn();
Log.e("ZoomIn", "Zoomed");
}
}, delay);
delay += 150; // Change this to whatever is good on the
// device
}
Log.e("ZoomIn", "completed");
}
});
}
After I execute this code, Logcat outputs "Thinks we should!" (basically flooding the logs) endlessly. But it never does anything with my handler... the actual zoomIn call never fires, and it just loops forever until I force-close my application. What am I doing wrong?
Your handler and the while loop are both executing their Runnables on the UI thread. So you've posted a bajillion runnables to the UI thread handler, but it doesn't matter, because the UI thread is busy executing your while loop and never gets to the point where it can execute the runnables you've posted to the handler. You'll have to modify your flow of control somewhat to get this to work - perhaps something like this:
public static void smoothZoomToSpan(final MapController controller,
MapView v, GeoPoint center, int latitudeSpan, int longitudeSpan) {
controller.animateTo(center, new Runnable());
}
private class ExecuteZoom implements Runnable {
static long delay;
#Override
public void run() {
if ((curLatSpan - 6000 > tarLatSpn)
|| (curLngSpan - 6000 > tarLngSpan)) {
handler.postDelayed(new ExecuteZoom(), delay);
delay += 150;
}
}
}
Clearly not a complete implementation, you might have to pass the constructor of the runnables some variables, etc; but hopefully this works out a bit better for you.
Related
In my android application I need to update different parts of the UI (actually a Fragment inside a ViewPager on a different time intervals. To do this I've created an Handler and 3 Runnables. With the postDelayed(Runnable, delay) method the Runnables should repeat themselves at scheduled time intervals.
Currently I have 1 runnable that must update a TextView every 100 ms, another that update a ProgressBar every 1000 ms and another one that checks some stuff every 2000 ms.
I saw the counter and the progress bar incrementing too fast and so I've put some code checking the delay between every call to the Run() method and I've discovered that the first runnable is executed every 58 ms and the progressbar's one running every 508 ms.
I've then tried to left only the first Runnable on the Handler (the counter one) and the Run() method get called every ~101 ms. So I've hypothized that other Runnables maybe interfer with the Message Queue schedule. I've then created one Handler for every Runnable but in that way the problem persist with 56~58 ms in the first Runnable and 508~510 ms on the second one.
Any suggestion on why this behaviour happen?
Here's part of my code:
private static final int TIME_STEP_COUNTER = 100;
private static final int TIME_STEP_PROGRESS = 1000;
private static final int TIME_STEP_DIRECTOR = 2000;
private Handler counterHandler, progressHandler, directorHandler;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
// some code here
directorThread = new DirectorThread(wwp,TIME_STEP_DIRECTOR);
if(directorHandler == null){
directorHandler = new Handler();
directorHandler.post(directorThread);
}
startCounting();
}
StartCounting() method
public void startCounting(){
stdCounterUpdater = new CounterUpdaterThread(textViewCounter,TIME_STEP_COUNTER, increment100ms);
progressUpdaterThread = new ProgressUpdaterThread(progressBar,TIME_STEP_PROGRESS,textViewPercentage);
fixerThread = new FixerThread(wwp,TIME_STEP_FIXER);
if(counterHandler == null){
counterHandler = new Handler();
}
counterHandler.post(stdCounterUpdater);
if(progressHandler == null){
progressHandler = new Handler();
}
progressHandler.postDelayed(progressBarInitThread, DELAY_INIT_PROGRESS);
progressHandler.postDelayed(progressUpdaterThread, DELAY_INIT_PROGRESS + INIT_PROGRESS_DURATION);
counterLayout.setVisibility(View.VISIBLE);
}
Threads
CounterUpdater
class CounterUpdaterThread implements Runnable{
public CounterUpdaterThread(TextView counterView, long deltaTime, float increment){
//Constructor with fields initialization
}
#Override
public void run(){
counter += increment;
changeCounterText();
if(counterHandler != null){
counterHandler.postDelayed(stdCounterUpdater,deltaTime);
}
}
}
ProgressUpdater
class ProgressUpdaterThread implements Runnable{
public ProgressUpdaterThread(ProgressBar pBar, long deltaTime, TextView percTW){
//Fields init
}
#Override
public void run(){
anim = new ProgressBarAnimation(progressBar, progress, progress + smoothScale);
progress += smoothScale;
anim.setDuration(PROGRESS_UPDATE_DURATION);
progressBar.startAnimation(anim);
percTW.setText(String.format(Locale.US,"%.1f", progressBar.getProgress()*100f/progressBar.getMax()) + "%");
if(progressHandler != null){
progressHandler.postDelayed(progressUpdaterThread,deltaTime);
}
}
}
DirectorThread
class DirectorThread implements Runnable{
public DirectorThread(WeeklyWorkPeriod wwp, long deltaTime){
//init
}
#Override
public void run(){
if(isStarted){
//....code.....
stopCounting();
isStarted = false;
//....code.....
}
}
else{
// ...code...
raiseMethod.requestProgressData(ProgressBarFragment.this,fragmentID);
startCounting();
isStarted = true;
}
}
if(directorHandler != null){
directorHandler.postDelayed(directorThread,deltaTime);
}
}
}
I've checked also these articles and some other question but with no results
Repeating Tasks
Handler Vs Timer
Handlers and Loopers
I just found the problem: wasn't about a single handler but about starting new callbacks in the DirectorThread. Just setting in the onCreateView() method isStarted to true solved the problem.
Among the other things I've replaced postDelayed() with postAtTime() as suggested by pskink cause it happens to be more accurate.
I got a fragment which got a control called RingProgress which is simply a ring that fills itself according to a percentage value given. For example, if I do:
ringProgress.setProgress(20);
It means that 20% of the ring will now be filled.
What I'm trying to do is to animate the ring being filled over a few seconds. So what I've tried to do is this:
#Override
public void onResume()
{
super.onResume();
HandlerThread handlerThread = new HandlerThread("countdown");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable()
{
#Override
public void run()
{
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
int totalSeconds = secondsToStart + minutesToStart * 60;
int secondsPassed = 0;
#Override
public void run()
{
if(secondsPassed == totalSeconds)
{
timer.cancel();
}
final int currentProgress = (secondsPassed / totalSeconds) * 100;
secondsPassed++;
getActivity().runOnUiThread(new Runnable()
{
#Override
public void run()
{
mRingProgressBar.setProgress(currentProgress);
}
});
}
}, 0, 1000);
}
});
}
The problem is that the update of the ring is not shown until the time is up. For example, if I set it for 5 seconds then when the fragment loads the ring is set to 0, then nothing happens for 5 seconds and then the ring is full with 100% all at once..
How can I start this animation properly?
I guess the problem is with
final int currentProgress = (secondsPassed / totalSeconds) * 100;
secondsPassed / totalSeconds return int value so it will be 0 or 1 only. And you multiply it to 100.
You have to use float or double instead
something like
final int currentProgress = Math.round(((float) secondsPassed)/((float) totalSeconds)*100f);
On this line:
Handler handler = new Handler(handlerThread.getLooper());
You are trying to get the looper from a handlerThread. But how sure you are the looper has already been initialized?
From the documentation of getLooper()
This method returns the Looper associated with this thread. If this thread not been started or for any reason is isAlive() returns false, this method will return null. If this thread has been started, this method will block until the looper has been initialized.
onLooperPrepared() is the callback, where you can be sure, that the Looper has been initialized, and therefore you can construct logics on that.
Thus, what you have to do, is to subclass HandlerThread and create appropriate logics from onLooperPrepared() callback.
Here's a nice post which will help you out. See implementation of MyWorkerThread class there.
Instead of using a handler, you could use a property animator as follows:
ObjectAnimator.ofInt(mRingProgressBar, "progress", 0, 100)
.setDuration(totalSeconds * 1000) //time is in miliseconds
.start();
This will find a method setProgress() in your mRingProgressBarand set the value according to the limits given. In the example above, 0 to 100.
You can read more about it here
Since you want to run on a different thread, you can use this handler in the top of the class:
private int progress = 0;
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
ringProgress.setProgress(progress);
progress += 20;
if (progress == 100) { //clear??
}
timerHandler.postDelayed(this, 1000);
}
};
In inCreate set the max:
ringProgress.setMax(100);
This will complete the animation within 5 seconds, then you can clear the animation. If you want smaller increments, change the line below (update every tenth of a second), and change the steps
timerHandler.postDelayed(this, 100);
Hello I'm trying to delay imageviews to give a perception that they are being taken out one by one. I've tried
Thread.Sleep
CountDownTimer
Runnable/Handler
But they either only delay once and both imageviews change at the same time or do not delay at all. For some reference I'm trying to do something like
private void delaycard(final int Card) {
newcard(Card); //Delay this before it is called
}
Willing to try/retry anything at this point
Off the top of my head, try something like this:
Handler h = new Handler();
//for the number of images we have
for (int i = 0; i < numImages; i++) {
//we create a runnable for that action
Runnable r = new Runnable() {
#Override
public void run() {
newCard(card);
}
};
//this is the amount of time to delay it by
delay = delay + 500;
//effectively, we're creating a series of runnables at the same time
//but they activate one after the other in .5s intervals
h.postDelayed(r, delay);
}
put this inside your method
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
newCard(Card);
}
}, 100);
I am making a piano app in which I need to emulate pressing keys in order to show the user the notes of a song. By using a handler, I am able to make a delay pressing up and down a key.
However, I am not able to make a delay between all the keys which have to be touched. I thought something like this, but I only see the last 2 notes get pressed and sound.
final String[] keys = {"1b","2w","9b","10w","11b","12w"};
handler = new Handler(Looper.getMainLooper());
for(int i = 0; i < keys.length - 1; i++) {
final int nextKey = i+1;
//Method in which I used other handler to delay pressing up and down
pressKey(keys[i]);
//Next key i would like to get pressed with a delay
handler.postDelayed(new Runnable() {
#Override
public void run() {
pressKey(keys[nextKey]);
}
},1500);
}
Instead of using for, use a runnable that will keep posting itself with the specified delay:
new Runnable()
{
int nextKey = 0;
#Override
public void run()
{
pressKey(keys[nextKey]);
if (++nextKey < keys.length)
handler.postDelayed(this, 1500);
// else no more keys
}
}.run();
I feel kinda stupid after all the night trying to figure it out. I just had to make a variable with the delay, and increment it in each iteration.
You can do this with a thread if in pressKey method there is no work that needs to be done in the UI thread.
new Thread(
new Runnable(){
#Override
public void run(){
for(int i = 0; i < keys.length - 1; i++) {
pressKey(keys[i]);
Thread.sleep(1500);
}
}
}
).run();
All,
I am newbie in android, just developing app to display the current Download/Upload Speed. I have got some tips from this Example. It uses TrafficStats.getTotalRxBytes() function that returns the total Bytes received after boot and increases monotonically.
So i used the below code, to display only the Current Available Speed. But i am not getting the result. it displays the Total Tx/Rx values only.
Is there any Alternative to achieve this? Any Code snippets would be much appreciated as i am a complete beginner.
Also, i cant understand below code. Can some one explain this?
private final Runnable mRunnable = new Runnable()
i need to refresh the data displayed in textView for every one second. I Guess
mHandler.postDelayed(mRunnable, 1000) ( );
is used to do that. is there any alternative? if not, how does would be the control flow when using PostDelayed function? (I am bit confused)
public class MainActivity extends Activity {
private Handler mHandler = new Handler();
private long mStartRX =0;
private long mStartTX = 0;
private static final int RESULT_SETTINGS = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.postDelayed(mRunnable, 1000);
}
private final Runnable mRunnable = new Runnable()
{
public void run()
{
long TxResult=0;
long RxResult=0;
long or1=0,or2=0;
long rxBytes = TrafficStats.getTotalRxBytes()- mStartRX-or1;
if (rxBytes<1024)
{
RxResult=0;
}
else if (rxBytes>1024)
{
// RxResult=0;
RxResult=RxResult+(rxBytes/1024);
}
TextView RX = (TextView)findViewById(R.id.rxOut);
//mStartRX=rxBytes;
TextView TX = (TextView)findViewById(R.id.txOut);
RX.setText(Long.toString(RxResult));
long txBytes = TrafficStats.getTotalTxBytes()- mStartTX-or2;
if (txBytes<1024)
{
TxResult=0;
}
else if (txBytes>1024)
{
TxResult=0;
TxResult=TxResult+(txBytes/1024);
}
TX.setText(Long.toString(TxResult));
or2=or2+txBytes;
or1=or1+rxBytes;
mHandler.postDelayed(mRunnable, 100);
}
};