I recently found myself looking at Fragment transactions and wondering precisely what each Fragment state meant. I vaguely had an idea of what added, attached, shown, hidden, detached and removed meant, but not the specific behaviors of each. I spent a morning looking through Android's code to better understand what happens to Fragments.
Here's a reference manual for what I learned. I looked into two aspects of Fragments: fragment states, and animations in transactions. This research was done primarily on the compatibility library. It's possible that some of the details below will differ for the 3.x+ implementation of Fragments.
All of the below support animations. Terminology note: when I say "configuration change", I mean when the device changes configuration (for example, from portrait to landscape) and the Activity must be destroyed/recreated.
remove() - These add and remove a Fragment from the FragmentManager. By default, it will begin showing the Fragment as well. During the transaction the returns of
Fragment.isRemoved() will be modified. These states are preserved on configuration change, so a Fragment that's added will remain added and can be retrieved again from the FragmentManager. Since a removed Fragment is no longer part of the FragmentManager, it will not be retrievable after a configuration change either.
detach() - These attach/detach a Fragment from the Activity (e.g., make it an active Fragment that can be seen). During the transaction the returns of
Fragment.isDetached() will be changed. These states are preserved on configuration change, which means that (unlike removing a Fragment) it is possible to detach a Fragment but then retrieve it later after configuration change (even if it's not actively being displayed). Even in a detached state, the Fragment runs through all lifecycle methods (except the ones that are related to being attached to an Activity) - for example,
onSaveInstanceState() will still be called even if the Fragment is detached (which is quite useful for maintaining state).
hide() - These show or hide a Fragment (in particular, it calls
View.setVisibility() on the Fragment's root View). During the transaction the returns of
Fragment.isHidden() will be modified. Showing/hiding Fragments states are NOT maintained on configuration change, meaning that if you hide a Fragment it will reappear on config change (for example, if the user rotates the screen).
replace() - Theoretically it is the exact same as removing all Fragments associated with a particular View, then adding a new Fragment in its place. I did not research this much (since I'm more interested in manual control of which Fragments are shown).
There are three different ways to animate Fragment transactions. These are ordered by precedence (in other words, the first method, if available, will be used; then the second, then the last).
Override your Fragment's
onCreateAnimator()method and return an animation. This is the only way to dynamically generate an animation in code (the other two methods rely on pre-configured animations from your resources directory). In the compatibility library, the method is
onCreateAnimation()(since the compatibility library uses animations instead of animators).
FragmentTransaction.setCustomAnimations(), referencing either animators or animations (depending on whether you're using the compatibility library or not). What is interesting is that
setCustomAnimations()affects all fragment transitions added to the transaction after it is called. So you need to call
setCustomAnimations()before you want it used, and you can actually setup multiple different custom animations for each part of a transaction (with a call to
Setup a style that defines window animations (from this style), then call
FragmentTransaction.setTransitionStyle()to specify that style and target the correct animation.
#3 works different in the compatibility library.
FragmentTransaction.setTransitionStyle() is completely ignored. Instead, it uses the specified transition to select a stock animation. So if you want custom animations in the compatibility library, you must use #1 or #2.