Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.fragment.app;
     18 
     19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.os.Bundle;
     22 import android.view.View;
     23 
     24 import androidx.annotation.AnimRes;
     25 import androidx.annotation.AnimatorRes;
     26 import androidx.annotation.IdRes;
     27 import androidx.annotation.IntDef;
     28 import androidx.annotation.NonNull;
     29 import androidx.annotation.Nullable;
     30 import androidx.annotation.RestrictTo;
     31 import androidx.annotation.StringRes;
     32 import androidx.annotation.StyleRes;
     33 
     34 import java.lang.annotation.Retention;
     35 import java.lang.annotation.RetentionPolicy;
     36 
     37 /**
     38  * Static library support version of the framework's {@link android.app.FragmentTransaction}.
     39  * Used to write apps that run on platforms prior to Android 3.0.  When running
     40  * on Android 3.0 or above, this implementation is still used; it does not try
     41  * to switch to the framework's implementation.  See the framework SDK
     42  * documentation for a class overview.
     43  */
     44 public abstract class FragmentTransaction {
     45     /**
     46      * Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
     47      */
     48     @NonNull
     49     public abstract FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag);
     50 
     51     /**
     52      * Calls {@link #add(int, Fragment, String)} with a null tag.
     53      */
     54     @NonNull
     55     public abstract FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment);
     56 
     57     /**
     58      * Add a fragment to the activity state.  This fragment may optionally
     59      * also have its view (if {@link Fragment#onCreateView Fragment.onCreateView}
     60      * returns non-null) into a container view of the activity.
     61      *
     62      * @param containerViewId Optional identifier of the container this fragment is
     63      * to be placed in.  If 0, it will not be placed in a container.
     64      * @param fragment The fragment to be added.  This fragment must not already
     65      * be added to the activity.
     66      * @param tag Optional tag name for the fragment, to later retrieve the
     67      * fragment with {@link FragmentManager#findFragmentByTag(String)
     68      * FragmentManager.findFragmentByTag(String)}.
     69      *
     70      * @return Returns the same FragmentTransaction instance.
     71      */
     72     @NonNull
     73     public abstract FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
     74             @Nullable String tag);
     75 
     76     /**
     77      * Calls {@link #replace(int, Fragment, String)} with a null tag.
     78      */
     79     @NonNull
     80     public abstract FragmentTransaction replace(@IdRes int containerViewId,
     81             @NonNull Fragment fragment);
     82 
     83     /**
     84      * Replace an existing fragment that was added to a container.  This is
     85      * essentially the same as calling {@link #remove(Fragment)} for all
     86      * currently added fragments that were added with the same containerViewId
     87      * and then {@link #add(int, Fragment, String)} with the same arguments
     88      * given here.
     89      *
     90      * @param containerViewId Identifier of the container whose fragment(s) are
     91      * to be replaced.
     92      * @param fragment The new fragment to place in the container.
     93      * @param tag Optional tag name for the fragment, to later retrieve the
     94      * fragment with {@link FragmentManager#findFragmentByTag(String)
     95      * FragmentManager.findFragmentByTag(String)}.
     96      *
     97      * @return Returns the same FragmentTransaction instance.
     98      */
     99     @NonNull
    100     public abstract FragmentTransaction replace(@IdRes int containerViewId,
    101             @NonNull Fragment fragment, @Nullable String tag);
    102 
    103     /**
    104      * Remove an existing fragment.  If it was added to a container, its view
    105      * is also removed from that container.
    106      *
    107      * @param fragment The fragment to be removed.
    108      *
    109      * @return Returns the same FragmentTransaction instance.
    110      */
    111     @NonNull
    112     public abstract FragmentTransaction remove(@NonNull Fragment fragment);
    113 
    114     /**
    115      * Hides an existing fragment.  This is only relevant for fragments whose
    116      * views have been added to a container, as this will cause the view to
    117      * be hidden.
    118      *
    119      * @param fragment The fragment to be hidden.
    120      *
    121      * @return Returns the same FragmentTransaction instance.
    122      */
    123     @NonNull
    124     public abstract FragmentTransaction hide(@NonNull Fragment fragment);
    125 
    126     /**
    127      * Shows a previously hidden fragment.  This is only relevant for fragments whose
    128      * views have been added to a container, as this will cause the view to
    129      * be shown.
    130      *
    131      * @param fragment The fragment to be shown.
    132      *
    133      * @return Returns the same FragmentTransaction instance.
    134      */
    135     @NonNull
    136     public abstract FragmentTransaction show(@NonNull Fragment fragment);
    137 
    138     /**
    139      * Detach the given fragment from the UI.  This is the same state as
    140      * when it is put on the back stack: the fragment is removed from
    141      * the UI, however its state is still being actively managed by the
    142      * fragment manager.  When going into this state its view hierarchy
    143      * is destroyed.
    144      *
    145      * @param fragment The fragment to be detached.
    146      *
    147      * @return Returns the same FragmentTransaction instance.
    148      */
    149     @NonNull
    150     public abstract FragmentTransaction detach(@NonNull Fragment fragment);
    151 
    152     /**
    153      * Re-attach a fragment after it had previously been detached from
    154      * the UI with {@link #detach(Fragment)}.  This
    155      * causes its view hierarchy to be re-created, attached to the UI,
    156      * and displayed.
    157      *
    158      * @param fragment The fragment to be attached.
    159      *
    160      * @return Returns the same FragmentTransaction instance.
    161      */
    162     @NonNull
    163     public abstract FragmentTransaction attach(@NonNull Fragment fragment);
    164 
    165     /**
    166      * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
    167      *
    168      * <p>The primary navigation fragment's
    169      * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
    170      * to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
    171      * if no ID or transaction name is provided to pop to. Navigation operations outside of the
    172      * fragment system may choose to delegate those actions to the primary navigation fragment
    173      * as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
    174      *
    175      * <p>The fragment provided must currently be added to the FragmentManager to be set as
    176      * a primary navigation fragment, or previously added as part of this transaction.</p>
    177      *
    178      * @param fragment the fragment to set as the primary navigation fragment
    179      * @return the same FragmentTransaction instance
    180      */
    181     @NonNull
    182     public abstract FragmentTransaction setPrimaryNavigationFragment(@Nullable Fragment fragment);
    183 
    184     /**
    185      * @return <code>true</code> if this transaction contains no operations,
    186      * <code>false</code> otherwise.
    187      */
    188     public abstract boolean isEmpty();
    189 
    190     /**
    191      * Bit mask that is set for all enter transitions.
    192      */
    193     public static final int TRANSIT_ENTER_MASK = 0x1000;
    194 
    195     /**
    196      * Bit mask that is set for all exit transitions.
    197      */
    198     public static final int TRANSIT_EXIT_MASK = 0x2000;
    199 
    200     /** @hide */
    201     @RestrictTo(LIBRARY_GROUP)
    202     @IntDef({TRANSIT_NONE, TRANSIT_FRAGMENT_OPEN, TRANSIT_FRAGMENT_CLOSE, TRANSIT_FRAGMENT_FADE})
    203     @Retention(RetentionPolicy.SOURCE)
    204     private @interface Transit {}
    205 
    206     /** Not set up for a transition. */
    207     public static final int TRANSIT_UNSET = -1;
    208     /** No animation for transition. */
    209     public static final int TRANSIT_NONE = 0;
    210     /** Fragment is being added onto the stack */
    211     public static final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK;
    212     /** Fragment is being removed from the stack */
    213     public static final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK;
    214     /** Fragment should simply fade in or out; that is, no strong navigation associated
    215      * with it except that it is appearing or disappearing for some reason. */
    216     public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK;
    217 
    218     /**
    219      * Set specific animation resources to run for the fragments that are
    220      * entering and exiting in this transaction. These animations will not be
    221      * played when popping the back stack.
    222      *
    223      * @param enter An animation or animator resource ID used for the enter animation on the
    224      *              view of the fragment being added or attached.
    225      * @param exit An animation or animator resource ID used for the exit animation on the
    226      *             view of the fragment being removed or detached.
    227      */
    228     @NonNull
    229     public abstract FragmentTransaction setCustomAnimations(@AnimatorRes @AnimRes int enter,
    230             @AnimatorRes @AnimRes int exit);
    231 
    232     /**
    233      * Set specific animation resources to run for the fragments that are
    234      * entering and exiting in this transaction. The <code>popEnter</code>
    235      * and <code>popExit</code> animations will be played for enter/exit
    236      * operations specifically when popping the back stack.
    237      *
    238      * @param enter An animation or animator resource ID used for the enter animation on the
    239      *              view of the fragment being added or attached.
    240      * @param exit An animation or animator resource ID used for the exit animation on the
    241      *             view of the fragment being removed or detached.
    242      * @param popEnter An animation or animator resource ID used for the enter animation on the
    243      *                 view of the fragment being readded or reattached caused by
    244      *                 {@link FragmentManager#popBackStack()} or similar methods.
    245      * @param popExit An animation or animator resource ID used for the enter animation on the
    246      *                view of the fragment being removed or detached caused by
    247      *                {@link FragmentManager#popBackStack()} or similar methods.
    248      */
    249     @NonNull
    250     public abstract FragmentTransaction setCustomAnimations(@AnimatorRes @AnimRes int enter,
    251             @AnimatorRes @AnimRes int exit, @AnimatorRes @AnimRes int popEnter,
    252             @AnimatorRes @AnimRes int popExit);
    253 
    254     /**
    255      * Used with custom Transitions to map a View from a removed or hidden
    256      * Fragment to a View from a shown or added Fragment.
    257      * <var>sharedElement</var> must have a unique transitionName in the View hierarchy.
    258      *
    259      * @param sharedElement A View in a disappearing Fragment to match with a View in an
    260      *                      appearing Fragment.
    261      * @param name The transitionName for a View in an appearing Fragment to match to the shared
    262      *             element.
    263      * @see Fragment#setSharedElementReturnTransition(Object)
    264      * @see Fragment#setSharedElementEnterTransition(Object)
    265      */
    266     @NonNull
    267     public abstract FragmentTransaction addSharedElement(@NonNull View sharedElement,
    268             @NonNull String name);
    269 
    270     /**
    271      * Select a standard transition animation for this transaction.  May be
    272      * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
    273      * {@link #TRANSIT_FRAGMENT_CLOSE}, or {@link #TRANSIT_FRAGMENT_FADE}.
    274      */
    275     @NonNull
    276     public abstract FragmentTransaction setTransition(@Transit int transit);
    277 
    278     /**
    279      * Set a custom style resource that will be used for resolving transit
    280      * animations.
    281      */
    282     @NonNull
    283     public abstract FragmentTransaction setTransitionStyle(@StyleRes int styleRes);
    284 
    285     /**
    286      * Add this transaction to the back stack.  This means that the transaction
    287      * will be remembered after it is committed, and will reverse its operation
    288      * when later popped off the stack.
    289      *
    290      * @param name An optional name for this back stack state, or null.
    291      */
    292     @NonNull
    293     public abstract FragmentTransaction addToBackStack(@Nullable String name);
    294 
    295     /**
    296      * Returns true if this FragmentTransaction is allowed to be added to the back
    297      * stack. If this method would return false, {@link #addToBackStack(String)}
    298      * will throw {@link IllegalStateException}.
    299      *
    300      * @return True if {@link #addToBackStack(String)} is permitted on this transaction.
    301      */
    302     public abstract boolean isAddToBackStackAllowed();
    303 
    304     /**
    305      * Disallow calls to {@link #addToBackStack(String)}. Any future calls to
    306      * addToBackStack will throw {@link IllegalStateException}. If addToBackStack
    307      * has already been called, this method will throw IllegalStateException.
    308      */
    309     @NonNull
    310     public abstract FragmentTransaction disallowAddToBackStack();
    311 
    312     /**
    313      * Set the full title to show as a bread crumb when this transaction
    314      * is on the back stack.
    315      *
    316      * @param res A string resource containing the title.
    317      */
    318     @NonNull
    319     public abstract FragmentTransaction setBreadCrumbTitle(@StringRes int res);
    320 
    321     /**
    322      * Like {@link #setBreadCrumbTitle(int)} but taking a raw string; this
    323      * method is <em>not</em> recommended, as the string can not be changed
    324      * later if the locale changes.
    325      */
    326     @NonNull
    327     public abstract FragmentTransaction setBreadCrumbTitle(@Nullable CharSequence text);
    328 
    329     /**
    330      * Set the short title to show as a bread crumb when this transaction
    331      * is on the back stack.
    332      *
    333      * @param res A string resource containing the title.
    334      */
    335     @NonNull
    336     public abstract FragmentTransaction setBreadCrumbShortTitle(@StringRes int res);
    337 
    338     /**
    339      * Like {@link #setBreadCrumbShortTitle(int)} but taking a raw string; this
    340      * method is <em>not</em> recommended, as the string can not be changed
    341      * later if the locale changes.
    342      */
    343     @NonNull
    344     public abstract FragmentTransaction setBreadCrumbShortTitle(@Nullable CharSequence text);
    345 
    346     /**
    347      * Sets whether or not to allow optimizing operations within and across
    348      * transactions. This will remove redundant operations, eliminating
    349      * operations that cancel. For example, if two transactions are executed
    350      * together, one that adds a fragment A and the next replaces it with fragment B,
    351      * the operations will cancel and only fragment B will be added. That means that
    352      * fragment A may not go through the creation/destruction lifecycle.
    353      * <p>
    354      * The side effect of removing redundant operations is that fragments may have state changes
    355      * out of the expected order. For example, one transaction adds fragment A,
    356      * a second adds fragment B, then a third removes fragment A. Without removing the redundant
    357      * operations, fragment B could expect that while it is being created, fragment A will also
    358      * exist because fragment A will be removed after fragment B was added.
    359      * With removing redundant operations, fragment B cannot expect fragment A to exist when
    360      * it has been created because fragment A's add/remove will be optimized out.
    361      * <p>
    362      * It can also reorder the state changes of Fragments to allow for better Transitions.
    363      * Added Fragments may have {@link Fragment#onCreate(Bundle)} called before replaced
    364      * Fragments have {@link Fragment#onDestroy()} called.
    365      * <p>
    366      * {@link Fragment#postponeEnterTransition()} requires {@code setReorderingAllowed(true)}.
    367      * <p>
    368      * The default is {@code false}.
    369      *
    370      * @param reorderingAllowed {@code true} to enable optimizing out redundant operations
    371      *                          or {@code false} to disable optimizing out redundant
    372      *                          operations on this transaction.
    373      */
    374     @NonNull
    375     public abstract FragmentTransaction setReorderingAllowed(boolean reorderingAllowed);
    376 
    377     /**
    378      * @deprecated This has been renamed {@link #setReorderingAllowed(boolean)}.
    379      */
    380     @Deprecated
    381     public abstract FragmentTransaction setAllowOptimization(boolean allowOptimization);
    382 
    383     /**
    384      * Add a Runnable to this transaction that will be run after this transaction has
    385      * been committed. If fragment transactions are {@link #setReorderingAllowed(boolean) optimized}
    386      * this may be after other subsequent fragment operations have also taken place, or operations
    387      * in this transaction may have been optimized out due to the presence of a subsequent
    388      * fragment transaction in the batch.
    389      *
    390      * <p>If a transaction is committed using {@link #commitAllowingStateLoss()} this runnable
    391      * may be executed when the FragmentManager is in a state where new transactions may not
    392      * be committed without allowing state loss.</p>
    393      *
    394      * <p><code>runOnCommit</code> may not be used with transactions
    395      * {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
    396      * with back stack state. {@link IllegalStateException} will be thrown if
    397      * {@link #addToBackStack(String)} has been previously called for this transaction
    398      * or if it is called after a call to <code>runOnCommit</code>.</p>
    399      *
    400      * @param runnable Runnable to add
    401      * @return this FragmentTransaction
    402      * @throws IllegalStateException if {@link #addToBackStack(String)} has been called
    403      */
    404     @NonNull
    405     public abstract FragmentTransaction runOnCommit(@NonNull Runnable runnable);
    406 
    407     /**
    408      * Schedules a commit of this transaction.  The commit does
    409      * not happen immediately; it will be scheduled as work on the main thread
    410      * to be done the next time that thread is ready.
    411      *
    412      * <p class="note">A transaction can only be committed with this method
    413      * prior to its containing activity saving its state.  If the commit is
    414      * attempted after that point, an exception will be thrown.  This is
    415      * because the state after the commit can be lost if the activity needs to
    416      * be restored from its state.  See {@link #commitAllowingStateLoss()} for
    417      * situations where it may be okay to lose the commit.</p>
    418      *
    419      * @return Returns the identifier of this transaction's back stack entry,
    420      * if {@link #addToBackStack(String)} had been called.  Otherwise, returns
    421      * a negative number.
    422      */
    423     public abstract int commit();
    424 
    425     /**
    426      * Like {@link #commit} but allows the commit to be executed after an
    427      * activity's state is saved.  This is dangerous because the commit can
    428      * be lost if the activity needs to later be restored from its state, so
    429      * this should only be used for cases where it is okay for the UI state
    430      * to change unexpectedly on the user.
    431      */
    432     public abstract int commitAllowingStateLoss();
    433 
    434     /**
    435      * Commits this transaction synchronously. Any added fragments will be
    436      * initialized and brought completely to the lifecycle state of their host
    437      * and any removed fragments will be torn down accordingly before this
    438      * call returns. Committing a transaction in this way allows fragments
    439      * to be added as dedicated, encapsulated components that monitor the
    440      * lifecycle state of their host while providing firmer ordering guarantees
    441      * around when those fragments are fully initialized and ready. Fragments
    442      * that manage views will have those views created and attached.
    443      *
    444      * <p>Calling <code>commitNow</code> is preferable to calling
    445      * {@link #commit()} followed by {@link FragmentManager#executePendingTransactions()}
    446      * as the latter will have the side effect of attempting to commit <em>all</em>
    447      * currently pending transactions whether that is the desired behavior
    448      * or not.</p>
    449      *
    450      * <p>Transactions committed in this way may not be added to the
    451      * FragmentManager's back stack, as doing so would break other expected
    452      * ordering guarantees for other asynchronously committed transactions.
    453      * This method will throw {@link IllegalStateException} if the transaction
    454      * previously requested to be added to the back stack with
    455      * {@link #addToBackStack(String)}.</p>
    456      *
    457      * <p class="note">A transaction can only be committed with this method
    458      * prior to its containing activity saving its state.  If the commit is
    459      * attempted after that point, an exception will be thrown.  This is
    460      * because the state after the commit can be lost if the activity needs to
    461      * be restored from its state.  See {@link #commitAllowingStateLoss()} for
    462      * situations where it may be okay to lose the commit.</p>
    463      */
    464     public abstract void commitNow();
    465 
    466     /**
    467      * Like {@link #commitNow} but allows the commit to be executed after an
    468      * activity's state is saved.  This is dangerous because the commit can
    469      * be lost if the activity needs to later be restored from its state, so
    470      * this should only be used for cases where it is okay for the UI state
    471      * to change unexpectedly on the user.
    472      */
    473     public abstract void commitNowAllowingStateLoss();
    474 }
    475