androidnullpointerexceptionviewanimator

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


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.


Solution

  • 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
              }
            });
          }