ViewAnimator's OnDraw throws NullPointerException if you remove child on onAnimationEnd

1k Views Asked by At

This is not a question, more like sharing with others a problem I encountered and how I resolved it.
Basically, I was trying to create a ViewAnimator, who would create additional children in response to user clicks.
To clean up after I have animated the next View in, I put

outAnimation.setAnimationListener(listener);

and in AnimationListener

public void onAnimationEnd(Animation animation) {
    viewAnimator.removeView(out);
}

Now, the problem with above approach is, immediately after onAnimationEnd, it throws a NullPointerException. Basically, it means, ViewAnimator is still using child view that is being animated out to draw. Since I have removed it, there is null there. I have done my research, and basically, it appears this is a known bug. See: Android Animation is not finished on onAnimationEnd

To resolve this, I have modified layout.

<ViewAnimator
    android:id="@+id/animator"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <FrameLayout
        android:id="@+id/container1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </FrameLayout>

    <FrameLayout
        android:id="@+id/container2"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </FrameLayout>
</ViewAnimator>

and onAnimationEnd I can safely call container.removeAllViews(). To animate a new view in, I select the hidden container and

container.addView(newView);
animator.setDisplayedChild(animator.indexOfChild(container));

I will be happy to see your comments and advice.

2

There are 2 best solutions below

1
On BEST ANSWER

I've run into this problem and used the view's post method to wait until the animation is really done:

      public void onAnimationEnd(Animation animation) {
        //Wait until the container has finished rendering to remove the items.
        view.post(new Runnable() {
          @Override
          public void run() {
            //remove view here
          }
        });
      }
0
On

I solved it. I have inAnimation and outAnimation. SO:

@Override
public void onAnimationEnd(Animation animation) {

    if(animationsFinished < 2) animationsFinished++;
    else{

        this.setInAnimation(null);  // Skipping this will cause trouble
        this.setOutAnimation(null); // Skipping this will cause trouble

        flipper.post(new Runnable(){

            @Override
            public void run() {
                flipper.removeView(previous);
            }

        });

        animationsFinished = 0;

    }


}