Fragment grab bag!
* Fragment#isStateSaved: report whether a given fragment has been through state save within its given FragmentManager. This will additionally echo the state of its child FragmentManager, indicating whether it is safe to perform transactions without losing state. * Fragment#setArguments can now be called at any time before a fragment's state is saved, not just before an internal index is assigned. This fixes an issue with assigning arguments during fragment inflation in some code paths. * FragmentTransaction#postOnCommit: Add a Runnable to a FragmentTransaction that will be executed once the operations in the transaction have been fully executed. Transaction optimization may mean that other transaction ops could run before this is executed, or that specific operations from this transaction were optimized out. (e.g. a fragment in this transaction was added, but then removed in a subsequent transaction before pending operations were executed.) This may not be used for transactions added to the back stack, as we cannot persist the runnable for later to guarantee running it when the transaction is reversed. Test: CTS Change-Id: I4eb90588135e30f287c6487aa62ebda231f3dad3
This commit is contained in:
@@ -4516,6 +4516,7 @@ package android.app {
|
||||
method public final boolean isInLayout();
|
||||
method public final boolean isRemoving();
|
||||
method public final boolean isResumed();
|
||||
method public final boolean isStateSaved();
|
||||
method public final boolean isVisible();
|
||||
method public void onActivityCreated(android.os.Bundle);
|
||||
method public void onActivityResult(int, int, android.content.Intent);
|
||||
@@ -4754,6 +4755,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
|
||||
method public abstract boolean isAddToBackStackAllowed();
|
||||
method public abstract boolean isEmpty();
|
||||
method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
|
||||
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
|
||||
|
||||
@@ -4676,6 +4676,7 @@ package android.app {
|
||||
method public final boolean isInLayout();
|
||||
method public final boolean isRemoving();
|
||||
method public final boolean isResumed();
|
||||
method public final boolean isStateSaved();
|
||||
method public final boolean isVisible();
|
||||
method public void onActivityCreated(android.os.Bundle);
|
||||
method public void onActivityResult(int, int, android.content.Intent);
|
||||
@@ -4914,6 +4915,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
|
||||
method public abstract boolean isAddToBackStackAllowed();
|
||||
method public abstract boolean isEmpty();
|
||||
method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
|
||||
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
|
||||
|
||||
@@ -4526,6 +4526,7 @@ package android.app {
|
||||
method public final boolean isInLayout();
|
||||
method public final boolean isRemoving();
|
||||
method public final boolean isResumed();
|
||||
method public final boolean isStateSaved();
|
||||
method public final boolean isVisible();
|
||||
method public void onActivityCreated(android.os.Bundle);
|
||||
method public void onActivityResult(int, int, android.content.Intent);
|
||||
@@ -4764,6 +4765,7 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
|
||||
method public abstract boolean isAddToBackStackAllowed();
|
||||
method public abstract boolean isEmpty();
|
||||
method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
|
||||
method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
|
||||
method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
|
||||
|
||||
@@ -220,6 +220,8 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
int mIndex = -1;
|
||||
boolean mAllowOptimization;
|
||||
|
||||
ArrayList<Runnable> mCommitRunnables;
|
||||
|
||||
int mBreadCrumbTitleRes;
|
||||
CharSequence mBreadCrumbTitleText;
|
||||
int mBreadCrumbShortTitleRes;
|
||||
@@ -620,6 +622,28 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentTransaction postOnCommit(Runnable runnable) {
|
||||
if (runnable == null) {
|
||||
throw new IllegalArgumentException("runnable cannot be null");
|
||||
}
|
||||
disallowAddToBackStack();
|
||||
if (mCommitRunnables == null) {
|
||||
mCommitRunnables = new ArrayList<>();
|
||||
}
|
||||
mCommitRunnables.add(runnable);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void runOnCommitRunnables() {
|
||||
if (mCommitRunnables != null) {
|
||||
for (int i = 0, N = mCommitRunnables.size(); i < N; i++) {
|
||||
mCommitRunnables.get(i).run();
|
||||
}
|
||||
mCommitRunnables = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int commit() {
|
||||
return commitInternal(false);
|
||||
}
|
||||
|
||||
@@ -714,14 +714,20 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the construction arguments for this fragment. This can only
|
||||
* be called before the fragment has been attached to its activity; that
|
||||
* is, you should call it immediately after constructing the fragment. The
|
||||
* arguments supplied here will be retained across fragment destroy and
|
||||
* Supply the construction arguments for this fragment.
|
||||
* The arguments supplied here will be retained across fragment destroy and
|
||||
* creation.
|
||||
*
|
||||
* <p>This method cannot be called if the fragment is added to a FragmentManager and
|
||||
* if {@link #isStateSaved()} would return true. Prior to {@link Build.VERSION_CODES#O},
|
||||
* this method may only be called if the fragment has not yet been added to a FragmentManager.
|
||||
* </p>
|
||||
*/
|
||||
public void setArguments(Bundle args) {
|
||||
if (mIndex >= 0) {
|
||||
// The isStateSaved requirement below was only added in Android O and is compatible
|
||||
// because it loosens previous requirements rather than making them more strict.
|
||||
// See method javadoc.
|
||||
if (mIndex >= 0 && isStateSaved()) {
|
||||
throw new IllegalStateException("Fragment already active");
|
||||
}
|
||||
mArguments = args;
|
||||
@@ -734,6 +740,21 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
|
||||
return mArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this fragment is added and its state has already been saved
|
||||
* by its host. Any operations that would change saved state should not be performed
|
||||
* if this method returns true, and some operations such as {@link #setArguments(Bundle)}
|
||||
* will fail.
|
||||
*
|
||||
* @return true if this fragment's state has already been saved by its host
|
||||
*/
|
||||
public final boolean isStateSaved() {
|
||||
if (mFragmentManager == null) {
|
||||
return false;
|
||||
}
|
||||
return mFragmentManager.isStateSaved();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial saved state that this Fragment should restore itself
|
||||
* from when first being constructed, as returned by
|
||||
|
||||
@@ -1787,6 +1787,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStateSaved() {
|
||||
return mStateSaved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to the queue of pending actions.
|
||||
*
|
||||
@@ -2108,6 +2112,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
freeBackStackIndex(record.mIndex);
|
||||
record.mIndex = -1;
|
||||
}
|
||||
record.runOnCommitRunnables();
|
||||
}
|
||||
|
||||
if (addToBackStack) {
|
||||
|
||||
@@ -303,6 +303,22 @@ public abstract class FragmentTransaction {
|
||||
*/
|
||||
public abstract FragmentTransaction setAllowOptimization(boolean allowOptimization);
|
||||
|
||||
/**
|
||||
* Add a Runnable to this transaction that will be run after this transaction has
|
||||
* been committed. If fragment transactions are {@link #setAllowOptimization(boolean) optimized}
|
||||
* this may be after other subsequent fragment operations have also taken place, or operations
|
||||
* in this transaction may have been optimized out due to the presence of a subsequent
|
||||
* fragment transaction in the batch.
|
||||
*
|
||||
* <p><code>postOnCommit</code> may not be used with transactions
|
||||
* {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
|
||||
* with back stack state.</p>
|
||||
*
|
||||
* @param runnable Runnable to add
|
||||
* @return this FragmentTransaction
|
||||
*/
|
||||
public abstract FragmentTransaction postOnCommit(Runnable runnable);
|
||||
|
||||
/**
|
||||
* Schedules a commit of this transaction. The commit does
|
||||
* not happen immediately; it will be scheduled as work on the main thread
|
||||
|
||||
Reference in New Issue
Block a user