Question

I have an animation which starts correctly the first time the fragment is displayed. However after an orientation change, it won't restart. The animation is an animation-list resource set as the background of an ImageView.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    final View root = inflater.inflate(R.layout.fragment_lead_manual,
            container, false);
    final ImageView badgeEntryView = (ImageView) root
            .findViewById(R.id.manual_image);
    mAnimation = (AnimationDrawable) badgeEntryView.getBackground();
    return root;
}

@Override
public void onResume() {
    super.onResume();
    mAnimation.start();
}

@Override
public void onPause() {
    super.onPause();
    mAnimation.stop();
}

EDIT: I forgot to add that the animation is inside a tab, which makes things more difficult. However, I've figured out the problem and will add the answer below.

Was it helpful?

Solution

There are two cases that need to be solved, based on when the tab is created:

  1. FIRST the tab is created, and SECOND its Activity is attached to the Window
  2. FIRST the Activity is attached to the Window, and SECOND the tab is created

Case one occurs if the tab is the first one displayed or during rotation. Case two occurs when the user switches to that tab because it's not the first. Let's handle each case separately:

Case 1: a) Create tab b) Attach to window

Calling AnimationDrawable.start() before it is attached to the window (i.e. inside onCreate() or onResume()) breaks the animation. As stated in the Android docs :

It's important to note that the start() method called on the AnimationDrawable cannot be called during the onCreate() method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged() method in your Activity, which will get called when Android brings your window into focus.

It's more difficult with Fragments, but basically the same. We override the method in the Activity and then call over to the Fragment:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        final FragmentManager fm = getFragmentManager();
        ManualLeadFragment manualFragment = (ManualLeadFragment) fm
                .findFragmentByTag(TAG_MANUAL);
        if (manualFragment != null) {
            manualFragment.startAnimation();
        }
    }
}

And then in the Fragment, implement startAnimation():

void startAnimation() {
    mAnimation.start();
}

Case 2: a) Attach to window b) Create tab

In this case, the call to onWindowFocusChanged() has already occurred and so the animation won't start. So we still need to start it during onResume(), but slightly differently:

@Override
public void onResume() {
    super.onResume();
    if (isVisible()) {
        startAnimation();
    }
}

This calls into the same startAnimation() method as in Case 1, but because the Fragment is already attached to the Window, it can be called during onResume().

Summary

AnimationDrawable.start() can only be called when the Fragment is visible. Sometimes it is visible during onResume(), and the animation can be started at that point. Other times it is not yet visible at that time, and then the overridden onWindowFocusChanged() method is called when when it becomes visible, and the animation is started then.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top