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);
Related
I want to create a basic "pokemon evolution" animation in my app , something like this:
I've been playing with this:
private void evolveAnimation(Pokemon selectedToEvolvePokemon) {
Drawable backgrounds[] = new Drawable[2];
Resources res = getResources();
backgrounds[0] = res.getDrawable(selectedPokemon.getImage(getContext()));
backgrounds[1] = res.getDrawable(selectedToEvolvePokemon.getImage(getContext()));
TransitionDrawable crossfader = new TransitionDrawable(backgrounds);
evolveTransition.setImageDrawable(crossfader);
crossfader.setCrossFadeEnabled(true);
crossfader.startTransition(3000); //The animation starts slow
crossfader.reverseTransition(3000);
crossfader.startTransition(2000);//It gets faster slow
crossfader.reverseTransition(2000);
crossfader.startTransition(1000); //And faster
crossfader.reverseTransition(1000);
}
However , this is not working as expected in the GIF posted below , how can I fix this?
EDIT:
I've changed the method to this:
private void doEvolve(TransitionDrawable crossfader, int durationMills) {
crossfader.startTransition(durationMills);
Handler h = new Handler(Looper.getMainLooper());
h.postDelayed(new Runnable() {
#Override
public void run() {
crossfader.reverseTransition(durationMills);
}
}, durationMills);
if (durationMills != 0) {
doEvolve(crossfader, durationMills - 100);
} else {
crossfader.startTransition(0);
}
}
However , works a bit strange.
currently you are starting all transitions at once, they should be queued
for example you may use some Handler and its postDelayed method, e.g.
crossfader.startTransition(3000);
Handler h = new Handler(Looper.getMainLooper());
h.postDelayed(new Runnable() {
#Override
public void run() {
crossfader.reverseTransition(3000);
}
}, 3000); // will start after startTransition duration
pack this code into some method which will take duration param and some callback informing that start/reverse pattern ended, then call this method again with shorter duration
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);
I know how to use handler and runnable to call a method at regular intervals of time. But now I want to call more than one method at regular interval of time. Below is the code in one of my classes:
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
#Override
public void run() {
for(int index = 0; index < count; index++) {
//Do something based on the index value
}
handler.postDelayed(runnable, 500);
}
};
Somewhere in my code I will have the below code to start the execution:
handler.postDelayed(runnable, 0);
So the first method corresponding to index 0 will be called first followed by other methods. And then there will be a 500ms delay to repeat the same.
But I also want a 500ms delay between the method calls. I mean when the for loop is executed. How can I do it using only one handler and runnable? How can I induce a 500ms delay between the method calls?
I would update the value of index across Handler invocations myself, and compare it to yourcount variable just like the for loop
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
private int index = 0;
#Override
public void run() {
//Do something based on the index value
index++;
if (index < count) {
handler.postDelayed(runnable, 500);
} else {
count = 0;
}
}
}
Besides, at the start you don't need to invoke postDelayed() with zero delay, you can directly call post().
I want to display 5 images on a Map View as map overlay with an interval of 1 minute each. I use sleep to make a delay. But it is not working. After all delay, the images are displaying altogether. How to do this? Please help
Look at this link. I think, it is, what you need
http://developer.android.com/resources/articles/timed-ui-updates.html
UPD:
Define in your activity:
private Handler mHandler = new Handler();
private int cnt = 0;
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
if (cnt < 5)
{
// Display new Image
mHandler.postDelayed(mUpdateTimeTask, 60000);
cnt++;
}
else
{
mHandler.removeCallbacks(this);
}
}
};
and call then somwhere in onCreate or onResume
mHandler.postDelayed(mUpdateTimeTask, 60000);
I have read several forums and examples on using invalidate() in order to update views immediately but I still do not understand why what I am doing will not work. The code below uses image buttons defined by "red", "blue", "green", and "yellow". I set a 1 second delay between each time I try and change a button's appearance. Please someone tell me what i'm doing wrong.
private void showPattern() {
if (correct == true) {
for (int k = 0; k < temp_basket.length; k++) {
if (temp_basket[k] == 0) {
red.setPressed(true);
red.invalidate();
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
red.setPressed(false);
red.invalidate();
}
});
}
}, 1000);
There are 3 more or these blocks after this one that are blue, green, and yellow.
Invaliadate puts a redraw message in the queue
As I see in your code, there are multiple redraws happening on after the other... the OS will try to optimize the rendering by clubbing multiple redraw messages into one (under the condition that there's no other message between them).
What you may want to do is:
private Handler myHandler = new Handler() {
public void handleMessage(Message msg)
{
switch(msg.what) { /* do your work */ }
}
};
Message msg = Message.obtain(myHandler);
msg.what = <some-number>;
msg.obj = <your-data-to-process>
if(myHandler.containsMessage(<same-number>) {
myHandler.removeMessages(<same-number>);
}
myHandler.sendMessage(msg);
You can also try using postInvalidate() method, which will cause the invalidate in the UI thread.