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 add(@onNull Fragment fragment, @Nullable String tag)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 add(@dRes int containerViewId, @NonNull Fragment fragment)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 add(@dRes int containerViewId, @NonNull Fragment fragment, @Nullable String tag)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 replace(@dRes int containerViewId, @NonNull Fragment fragment)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 replace(@dRes int containerViewId, @NonNull Fragment fragment, @Nullable String tag)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 remove(@onNull Fragment fragment)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 hide(@onNull Fragment fragment)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 show(@onNull Fragment fragment)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 detach(@onNull Fragment fragment)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 attach(@onNull Fragment fragment)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 setPrimaryNavigationFragment(@ullable Fragment fragment)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 */ isEmpty()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 setCustomAnimations(@nimatorRes @nimRes int enter, @AnimatorRes @AnimRes int exit)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 setCustomAnimations(@nimatorRes @nimRes int enter, @AnimatorRes @AnimRes int exit, @AnimatorRes @AnimRes int popEnter, @AnimatorRes @AnimRes int popExit)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 addSharedElement(@onNull View sharedElement, @NonNull String name)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 setTransition(@ransit int transit)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 setTransitionStyle(@tyleRes int styleRes)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 addToBackStack(@ullable String name)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 */ isAddToBackStackAllowed()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 disallowAddToBackStack()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 setBreadCrumbTitle(@tringRes int res)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 setBreadCrumbTitle(@ullable CharSequence text)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 setBreadCrumbShortTitle(@tringRes int res)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 setBreadCrumbShortTitle(@ullable CharSequence text)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 setReorderingAllowed(boolean reorderingAllowed)375 public abstract FragmentTransaction setReorderingAllowed(boolean reorderingAllowed); 376 377 /** 378 * @deprecated This has been renamed {@link #setReorderingAllowed(boolean)}. 379 */ 380 @Deprecated setAllowOptimization(boolean allowOptimization)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 runOnCommit(@onNull Runnable runnable)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 */ commit()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 */ commitAllowingStateLoss()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 */ commitNow()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 */ commitNowAllowingStateLoss()473 public abstract void commitNowAllowingStateLoss(); 474 } 475