How reliable is onAnimationEndListener? - java

I made an mediaplayer app with animations when the users plays the next song, the album art fades out and the album art for the next song fades in.
I first start the fade out animation and if this animation ends i send a broadcast to start the second song.
I would like to know if onAnimationEnd is reliable and will always called because if not then my app basically wouldn't work anymore for playing next/prev song.
private void nextSong(){
mAlbumArtLarge.startAnimation(fadeOutAnimation);
mAlbumIvBottom.startAnimation(fadeOutAnimation);
mAlbumArt.startAnimation(fadeOutAnimation);
tvSongTitle.startAnimation(fadeOutAnimation);
tvArtistName.startAnimation(fadeOutAnimation);
tvSongListSize.startAnimation(fadeOutAnimation);
fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (Main.getInstance().mServiceIsBound) {
Main.getInstance().mediaPlayerService.startActionNextSong(getApplication(), songList, songIndex);
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}

From my experience it wasn't called in case you run an animation during the start onCreate()of activity in view.post{ startAnimation() } and by going to background during beginning of animation it didn't called the listener. Eventually the problem for me was usage of post(Runnable) on queue to execute on main thread, as it was called in onCreate(). I had resolved it by using onWindowFocusChanged() + post{}. Will update my answer after sometime of using it in production. For now tested it on different devices/APIs no problem occurred.
To think of : you can add some (safety workaround) Handler with timer (like 5 sec if animation doesn't ends you do next step there after 5s)

Related

Inconsistent results with startAnimation in Android Studio

I'm trying to animate my imagebuttons by making them wobble when clicked.
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.buttonStart:
buttonStart.startAnimation(wobble);
Intent i;
i = new Intent(this, CityRendActivity.class);
startActivity(i);
break;
}
}
When I click my Start button, it very slowly starts to wobble, but only appears to shake back and forth like 3 times, and a lot slower than I have defined in the xml file. When I remove the lines that contain the intent code, the wobble works perfectly and the button shakes 5 times quickly (though now of course it doesn't load up my other activity).
So why would the code after the wobble animation effect how it's run? Doesn't each line get resolved individually before proceeding? I don't understand how loading up a different activity would effect the animation that I've set up. Any thoughts? Thanks.
Try adding animation listener for your animation and onAnimationEnd() start your Activity Intent.
wobble.setAnimationListener(new AnimationListener(){
#Override
public void onAnimationStart(Animation animation){}
#Override
public void onAnimationRepeat(Animation animation){}
#Override
public void onAnimationEnd(Animation animation){
startActivity(new Intent(YourCurrentActivity.this, CityRendActivity.class)); // if the code is in Fragment, then replace YourCurrentActivity.this by getActivity()
}
});
Actually In this code. animation and starting a new activity will execute at a same time. that will disturb the animation in between. so delay the starting of activity with your animation time. so that animation will completed and then your Activity will start.hope this work for you.
new Handler().postDelayed(new Runnable(){
#Overide
void run(){
startActivity(new Intent(this, CityRendActivity.class));
}
},time_ofanimation);

Variables change before onAnimationEnd runs

My problem is most likely because of bad design, but anyway :
I have an ArrayList that holds a bunch of ImageViews (terrain blocks).
Then, I iterated through to create the ImageViews programatically, and then set their animation to an animation called moveLeft which just makes the ImageView move left for 10 seconds.
Right after the animation ends, I need to set the ImageView's visibility to GONE because it will be off-screen by then.
The problem is that I used an int count to hold the total number of ImageViews.
moveLeft.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
terrainArray.get(count - 1).setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
I'm constantly making new terrain blocks, which means my count variable is constantly changing.
However, onAnimationEnd doesn't run with the same value of count as it does when the animation starts. As a result, it ends up setting some othhe block's visibility to GONE instead.
This is because onAnimationEnd didn't actually run until 10 seconds AFTER the block was created, because the animation lasts 10 seconds.
As a result, I'm left with the wrong block number when I want to set its visibility because MORE blocks are being created AS the animation is running. (therefore increasing count's value)
Is there some sort of way I could store count's current value on the onAnimationStart method
and then pass that same value to the onAnimationEnd method? (And make it work for up to infinite numbers of terrain blocks? Also, there's only one listener, and multiple blocks can possibly end their animation at the same time.)
This is easy. If you are sure that you need the exact value of count that is at the onAnimationStart(), then create a variable in the anonymous class. Save count value in onAnimationStart() and use it in onAnimationEnd()
You can copy the following snippet.
moveLeft.setAnimationListener(new Animation.AnimationListener() {
private int mCount = 0;
#Override
public void onAnimationStart(Animation animation) {
mCount = count;
}
#Override
public void onAnimationEnd(Animation animation) {
terrainArray.get(mCount - 1).setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
Hope this helps. But, I am afraid there could be bigger design problems. Be careful boss :)

timer calling activity after back button is pressed

I am trying to make simple maths game. Aim of the game is to answer so many questions right in a certain time limit.
I have a timer which counts down and calls my final screen to set your highscore. Problem is, when testing the app if the back button is pressed before timer is done, it seems to continue in the background and my highScore screen randomly appears. How can I make this stop?
Here is the code for my timer:
/**
* timer method
*/
public void timer() {
new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Intent i = new Intent(MainActivity.this, HighScoreScreen.class);
i.putExtra("Score", score);
startActivity(i);
resetScore();
finish();
}
}.start();
}
One solution to this very particular problem would be to override onBackPressed and cancel your timer there. On the other hand, if you want to cancel the timer when there is any interruption (e.g. user receives a call while using your app), you could perhaps place the cancel call in a lifecycle method like onStop.

Android execute when multiple tasks are done

I'm working on an app that downloads information from my server after an NFC card has been detected.
When a card is detected, I start
- an Asynctask to download some data from my server
- an animation of a popup appearing on the screen
After both the asynctask and the animation are done, I want to start a method that displays the downloaded data in the popup.
What is the correct way to trigger this new method? It can only start when both conditions are met.
In the async task you use to download data add the onPostExecute method to remove the animation popup and show the downloaded data as well like this :
protected void onPostExecute(Long result) {
//put code to disable animation popup
//code for displaying downloaded data popup
}
For more info check out http://developer.android.com/reference/android/os/AsyncTask.html
you Animation object has the method setAnimationLister. It takes as parameter a Class Object that implements the interface Animation.AnimationListener . This interface requires three methods to be implemented:
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
The onAnimationEnd is triggered when the animation ends. If I have not misunderstood you, this is what you need
EDIT:
you could have two booleans value, boolean animationFinished = false, downloadFinished = false; When onPostExecute is called put downloadFinished to true and call yourMethod.
When onAnimationEnd is triggered animationFinished = true and call yourMethod. yourMethod should start like:
if (!animationFinished || !downloadFinished)
return;

Two animations one after another

I want to make 2 animation on activity for 2 images, and I want to do it with 2 conditions:
1. I want to start the animation after the activity finished to load to page, so instead of putting animation code under onCreate i put it under onResume is that OK? There is a better way to do it?
2. I want the second animation will start only after the first animation is finished...
Thanks
You'll want to use an Animation.AnimationListner You can set one on your first animation that will get a callback when the animation is complete. Inside that callback you can add the code that will start the second animation.
Depending on the API level you are coding for you can use AnimationSet or AnimatorSet. Also if you are extending View or one of its subclasses you can override View.onAnimationStart() and View.onAnimationFinish(). Or use the listener Tim mentions.
public class SplashActivity extends Activity{
Animation FadeInanimation, FadeOutanimation;
ImageView img;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
img= (ImageView) findViewById(R.id.img);
//Your Code Block....
FadeInanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadein);
//FadeInanimation.setRepeatCount(Animation.INFINITE);
//FadeInanimation.setRepeatMode(Animation.RESTART);
FadeInanimation.setAnimationListener(FadeInAnimationListener);
FadeOutanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadeout);
//FadeOutanimation.setRepeatCount(Animation.INFINITE);
//FadeOutanimation.setRepeatMode(Animation.RESTART);
FadeOutanimation.setAnimationListener(fadeOutAnimationListener);
img.startAnimation(FadeInanimation);
}
AnimationListener FadeInAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
plane.startAnimation(FadeOutanimation);
}
};
}

Categories

Resources