8

When I run this code inside my custom view, onAnimationStart and onAnimationEnd are kept being called repeatedly. Isn't that weird? As an Android programmer, I expected them to be called only once respectively.

    final ViewPropertyAnimator animator = animate().setDuration(1000).alpha(0.0f);
    animator.setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            Utils.log("----------------start");
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            Utils.log("--------- end");
        }
    }).start();

But then I tried to fix the problem by removing the listener when onAnimationEnd gets called by ViewPropertyAnimator's setListener(null) but it never worked despite what's written in the docs:

public ViewPropertyAnimator setListener (Animator.AnimatorListener listener)

Added in API level 12
Sets a listener for events in the underlying Animators that run the property animations.

Parameters
listener    The listener to be called with AnimatorListener events. A value of null removes any existing listener.
Returns
This object, allowing calls to methods in this class to be chained.

Has anyone else run into this weird problem? maybe it's an Android's bug?

Leo
  • 1,433
  • 23
  • 40
  • where do you call animator.start() ? – pskink Apr 02 '15 at 08:00
  • inside my custom view, btw, actually I think I don't even need to call it, the animation will be started by next opportunity (maybe next frame). I read it somewhere in the docs – Leo Apr 02 '15 at 08:06
  • what does it nean "inside my custom view"? what method? – pskink Apr 02 '15 at 08:10
  • oh, sorry, I called it onTouch event when the touch action is ACTION_UP || ACTION_CANCEL – Leo Apr 02 '15 at 08:11

1 Answers1

29

I just ran into this issue but without the custom view.

In my case, I had two animations on the same view. A show and hide.

So it was

showView(){
  myView.animate().translationY(myView.getHeight()).setListener(new ...{
    ...
    onAnimationEnd(Animation animation){
     hideView();
    }
    ...}).start();
}
hideView(){
  myView.animate().translationY(0).start();
}

When hideView() finished, it would call itself again. This is because the old listener was still set. The key to fixing it ended up being to set the listener to null in the second animation. e.g.

hideView(){
  myView.animate().translationY(0).setListener(null).start();
}
Jon F Hancock
  • 3,349
  • 3
  • 23
  • 26
  • 7
    setListener(null) can actually be called from within the listener callback itself which, makes the code tidier since then the listener cleans up after itself. – Safa Alai Apr 25 '15 at 21:25
  • 1
    @Mauker you can just use myView.animate().setListener(null); in onAnimationEnd.. Seems kind of strange but looking at the android source the animate() method returns the previously created ViewPropertyAnimator so you're just getting that value back and setting the listener to null. – Matt Wolfe Apr 25 '16 at 20:30