资料
Fragment生命周期为什么要通过Fragment.setArguments(Bundle)传递参数
单独
问题:
动态方式,静态方式添加
- 随Activity启动
- 动态添加
- 回退栈
- onSaveInstance
静态方式添加Fragment
mHost 是这个
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
static final int INITIALIZING = -1; // Not yet attached.
static final int ATTACHED = 0; // Attached to the host.
static final int CREATED = 1; // Created.
static final int VIEW_CREATED = 2; // View Created.
static final int AWAITING_EXIT_EFFECTS = 3; // Downward state, awaiting exit effects
static final int ACTIVITY_CREATED = 4; // Fully created, not st加粗样式arted.
static final int STARTED = 5; // Created and started, not resumed.
static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
static final int RESUMED = 7; // Created started and resumed.
Activity和Fragment的生命周期
Activity -> onCreate*
Fragment -> onAttach
Fragment -> onCreate
Activity -> onStart*
Fragment -> onCreateView
Fragment -> onViewCreated
Fragment -> onStart
Activity -> onResume*
Fragment -> onResume
Activity -> onPause*
Fragment -> onPause
Activity -> onStop*
Fragment -> onStop
Activity -> onDestroy*
Fragment -> onDestroyView
Fragment -> onDestroy
Fragment -> onDetach
0 = {StackTraceElement@21058} "dalvik.system.VMStack.getThreadStackTrace(Native Method)"
1 = {StackTraceElement@21059} "java.lang.Thread.getStackTrace(Thread.java:1724)"
2 = {StackTraceElement@21060} "java.lang.Thread.getAllStackTraces(Thread.java:1800)"
3 = {StackTraceElement@21061} "androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)"
4 = {StackTraceElement@21062} "androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2196)"
5 = {StackTraceElement@21063} "androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)"
6 = {StackTraceElement@21064} "androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1971)"
7 = {StackTraceElement@21065} "androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:311)"
8 = {StackTraceElement@21066} "androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:180)"
9 = {StackTraceElement@21067} "androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:52)"
10 = {StackTraceElement@21068} "androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)"
11 = {StackTraceElement@21069} "androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)"
12 = {StackTraceElement@21070} "androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)"
13 = {StackTraceElement@21071} "android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1073)"
14 = {StackTraceElement@21072} "android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1001)"
15 = {StackTraceElement@21073} "android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)"
16 = {StackTraceElement@21074} "android.view.LayoutInflater.rInflate(LayoutInflater.java:1127)"
17 = {StackTraceElement@21075} "android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)"
18 = {StackTraceElement@21076} "android.view.LayoutInflater.inflate(LayoutInflater.java:686)"
19 = {StackTraceElement@21077} "android.view.LayoutInflater.inflate(LayoutInflater.java:538)"
20 = {StackTraceElement@21078} "android.view.LayoutInflater.inflate(LayoutInflater.java:485)"
21 = {StackTraceElement@21079} "androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:706)"
22 = {StackTraceElement@21080} "androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)"
23 = {StackTraceElement@21081} "com.joyy.android_project.MainActivity.onCreate(MainActivity.kt:21)"
24 = {StackTraceElement@21082} "android.app.Activity.performCreate(Activity.java:8051)"
25 = {StackTraceElement@21083} "android.app.Activity.performCreate(Activity.java:8031)"
26 = {StackTraceElement@21084} "android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)"
27 = {StackTraceElement@21085} "android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)"
28 = {StackTraceElement@21086} "android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)"
29 = {StackTraceElement@21087} "android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)"
30 = {StackTraceElement@21088} "android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)"
31 = {StackTraceElement@21089} "android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)"
32 = {StackTraceElement@21090} "android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)"
33 = {StackTraceElement@21091} "android.os.Handler.dispatchMessage(Handler.java:106)"
34 = {StackTraceElement@21092} "android.os.Looper.loopOnce(Looper.java:201)"
35 = {StackTraceElement@21093} "android.os.Looper.loop(Looper.java:288)"
36 = {StackTraceElement@21094} "android.app.ActivityThread.main(ActivityThread.java:7839)"
37 = {StackTraceElement@21095} "java.lang.reflect.Method.invoke(Native Method)"
38 = {StackTraceElement@21096} "com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)"
39 = {StackTraceElement@21097} "com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)"
静态方式#创建FragmentContainerView的时候启动事物
FragmentContainerView(@NonNull Context context, @NonNull AttributeSet attrs, @NonNull FragmentManager fm) {
super(context, attrs);
String name = attrs.getClassAttribute();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FragmentContainerView);
if (name == null) {
name = a.getString(R.styleable.FragmentContainerView_android_name);
}
String tag = a.getString(R.styleable.FragmentContainerView_android_tag);
a.recycle();
int id = getId();
Fragment existingFragment = fm.findFragmentById(id);
// If there is a name and there is no existing fragment,
// we should add an inflated Fragment to the view.
if (name != null && existingFragment == null) {
if (id <= 0) {
final String tagMessage = tag != null
? " with tag " + tag
: "";
throw new IllegalStateException("FragmentContainerView must have an android:id to "
+ "add Fragment " + name + tagMessage);
}
Fragment containerFragment = fm.getFragmentFactory().instantiate(context.getClassLoader(), name);
containerFragment.onInflate(context, attrs, null);
fm.beginTransaction()
.setReorderingAllowed(true)
.add(this, containerFragment, tag)
.commitNowAllowingStateLoss();
}
fm.onContainerAvailable(this);
在构造函数中commit
fm.beginTransaction()
.setReorderingAllowed(true)
.add(this, containerFragment, tag)
.commitNowAllowingStateLoss();
FragmentManager是设置LayoutInflater.setFactory2()
addFragment的时候,就保存在FragmentStore中
FragmentStateManager addFragment(@NonNull Fragment fragment) {
if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
fragment.mFragmentManager = this;
mFragmentStore.makeActive(fragmentStateManager);
if (!fragment.mDetached) {
mFragmentStore.addFragment(fragment);
fragment.mRemoving = false;
if (fragment.mView == null) {
fragment.mHiddenChanged = false;
}
if (isMenuAvailable(fragment)) {
mNeedMenuInvalidate = true;
}
}
return fragmentStateManager;
}
void makeActive(@NonNull FragmentStateManager newlyActive) {
Fragment f = newlyActive.getFragment();
if (containsActiveFragment(f.mWho)) {
return;
}
mActive.put(f.mWho, newlyActive);
if (f.mRetainInstanceChangedWhileDetached) {
if (f.mRetainInstance) {
mNonConfig.addRetainedFragment(f);
} else {
mNonConfig.removeRetainedFragment(f);
}
f.mRetainInstanceChangedWhileDetached = false;
}
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Added fragment to active set " + f);
}
}
总结:
- FragmentContainerView在Layout的时候有一个添加事物的操作
- 重写了setFactory2方法,设置了自定义的onCreateView
- 跟随着Activity的生命周期,dispatch Fragment的状态
动态方式添加Fragment
val manager = supportFragmentManager
val beginTransaction = manager.beginTransaction()
val oneFragment = OneFragment()
beginTransaction.replace(R.id.dynamicContainer, oneFragment)
beginTransaction.commit()
FragmentTransaction中创建BackStackRecord
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
FragmentTransactio#replace
@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
final Class<?> fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
// 保存存放mContainerId
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment));
}
// Op的构造函数
Op(int cmd, Fragment fragment) {
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}
ArrayList<Op> mOps = new ArrayList<>();
// 添加到Op集合中
void addOp(Op op) {
mOps.add(op);
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
BackStackRecord#commit
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", pw);
pw.close();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex();
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
FragmentManager#scheduleCommit
void scheduleCommit() {
synchronized (mPendingActions) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
updateOnBackPressedCallbackEnabled();
}
}
}
private Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions(true);
}
};
boolean execPendingActions(boolean allowStateLoss) {
ensureExecReady(allowStateLoss);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
updateOnBackPressedCallbackEnabled();
doPendingDeferredStart();
mFragmentStore.burpActive();
return didSomething;
}
private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isPop) {
boolean didSomething = false;
synchronized (mPendingActions) {
if (mPendingActions.isEmpty()) {
return false;
}
final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
// BackStackRecord
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Run: " + this);
}
records.add(this);
isRecordPop.add(false);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
return true;
}
// 去除多余的
private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
if (records.isEmpty()) {
return;
}
if (records.size() != isRecordPop.size()) {
throw new IllegalStateException("Internal error with the back stack records");
}
// Force start of any postponed transactions that interact with scheduled transactions:
executePostponedTransaction(records, isRecordPop);
final int numRecords = records.size();
int startIndex = 0;
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
final boolean canReorder = records.get(recordNum).mReorderingAllowed;
if (!canReorder) {
// execute all previous transactions
if (startIndex != recordNum) {
executeOpsTogether(records, isRecordPop, startIndex, recordNum);
}
// execute all pop operations that don't allow reordering together or
// one add operation
int reorderingEnd = recordNum + 1;
if (isRecordPop.get(recordNum)) {
while (reorderingEnd < numRecords
&& isRecordPop.get(reorderingEnd)
&& !records.get(reorderingEnd).mReorderingAllowed) {
reorderingEnd++;
}
}
executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
startIndex = reorderingEnd;
recordNum = reorderingEnd - 1;
}
}
if (startIndex != numRecords) {
executeOpsTogether(records, isRecordPop, startIndex, numRecords);
}
}
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.mCmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.mFragment);
break;
case OP_REMOVE:
case OP_DETACH: {
added.remove(op.mFragment);
if (op.mFragment == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
opNum++;
oldPrimaryNav = null;
}
}
break;
case OP_REPLACE: {
final Fragment f = op.mFragment;
final int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
final Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
// This is duplicated from above since we only make
// a single pass for expanding ops. Unset any outgoing primary nav.
if (old == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
opNum++;
oldPrimaryNav = null;
}
final Op removeOp = new Op(OP_REMOVE, old);
removeOp.mEnterAnim = op.mEnterAnim;
removeOp.mPopEnterAnim = op.mPopEnterAnim;
removeOp.mExitAnim = op.mExitAnim;
removeOp.mPopExitAnim = op.mPopExitAnim;
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
op.mCmd = OP_ADD;
added.add(f);
}
}
break;
case OP_SET_PRIMARY_NAV: {
// It's ok if this is null, that means we will restore to no active
// primary navigation fragment on a pop.
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
opNum++;
// Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
oldPrimaryNav = op.mFragment;
}
break;
}
}
return oldPrimaryNav;
}
/**
* Executes the operations contained within this transaction. The Fragment states will only
* be modified if optimizations are not allowed.
*/
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
if (f != null) {
f.setPopDirection(false);
f.setNextTransition(mTransition);
f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
}
switch (op.mCmd) {
case OP_ADD:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.addFragment(f);
break;
case OP_REMOVE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.attachFragment(f);
break;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
case OP_SET_MAX_LIFECYCLE:
mManager.setMaxLifecycle(f, op.mCurrentMaxState);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
}
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
if (!FragmentManager.USE_STATE_MANAGER) {
mManager.moveFragmentToExpectedState(f);
}
}
}
if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}
// FragmentStateManager
FragmentStateManager addFragment(@NonNull Fragment fragment) {
if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
fragment.mFragmentManager = this;
mFragmentStore.makeActive(fragmentStateManager);
if (!fragment.mDetached) {
mFragmentStore.addFragment(fragment);
fragment.mRemoving = false;
if (fragment.mView == null) {
fragment.mHiddenChanged = false;
}
if (isMenuAvailable(fragment)) {
mNeedMenuInvalidate = true;
}
}
return fragmentStateManager;
}
FragmentManager#显示在界面上
private void completeShowHideFragment(@NonNull final Fragment fragment) {
if (fragment.mView != null) {
FragmentAnim.AnimationOrAnimator anim = FragmentAnim.loadAnimation(
mHost.getContext(), fragment, !fragment.mHidden, fragment.getPopDirection());
if (anim != null && anim.animator != null) {
anim.animator.setTarget(fragment.mView);
if (fragment.mHidden) {
if (fragment.isHideReplaced()) {
fragment.setHideReplaced(false);
} else {
final ViewGroup container = fragment.mContainer;
final View animatingView = fragment.mView;
container.startViewTransition(animatingView);
// Delay the actual hide operation until the animation finishes,
// otherwise the fragment will just immediately disappear
anim.animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
container.endViewTransition(animatingView);
animation.removeListener(this);
if (fragment.mView != null && fragment.mHidden) {
fragment.mView.setVisibility(View.GONE);
}
}
});
}
} else {
fragment.mView.setVisibility(View.VISIBLE);
}
anim.animator.start();
} else {
if (anim != null) {
fragment.mView.startAnimation(anim.animation);
anim.animation.start();
}
final int visibility = fragment.mHidden && !fragment.isHideReplaced()
? View.GONE
: View.VISIBLE;
fragment.mView.setVisibility(visibility);
if (fragment.isHideReplaced()) {
fragment.setHideReplaced(false);
}
}
}
invalidateMenuForFragment(fragment);
fragment.mHiddenChanged = false;
fragment.onHiddenChanged(fragment.mHidden);
}
show 是直接addView
commit 是setVisible
事务内存管理
入栈:
mIndex = mManager.allocBackStackIndex(this);
mBackStackIndices.add(bse);
出栈:
freeBackStackIndex()
mTmpRecords,mTmpRecords
四种不同的提交方式
commit
正常的方式
commitInternal -> enqueueAction -> scheduleCommit -> execPendingActions -> startPendingDeferredFragments -> performPendingDeferredStart -> fragmentStateManager.moveToExpectedState() -> controller.enqueueShow( -> 显示界面
很多个操作放在一起,通过handler的post调用
commitAllowingStateLoss
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
if (mHost == null) {
if (mDestroyed) {
throw new IllegalStateException("FragmentManager has been destroyed");
} else {
throw new IllegalStateException("FragmentManager has not been attached to a "
+ "host.");
}
}
checkStateLoss();
}
commitNow
@Override
public void commitNow() {
disallowAddToBackStack(); // 设置标识位mAllowAddToBackStack = false;
mManager.execSingleAction(this, false);
}
void execSingleAction(@NonNull OpGenerator action, boolean allowStateLoss) {
if (allowStateLoss && (mHost == null || mDestroyed)) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
ensureExecReady(allowStateLoss);
// 直接放入mTmpRecords中, 然后去掉冗余操作
if (action.generateOps(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
}
updateOnBackPressedCallbackEnabled();
doPendingDeferredStart(); // 开始执行流程
mFragmentStore.burpActive();
}
execSingleAction -> startPendingDeferredFragments -> performPendingDeferredStart -> fragmentStateManager.moveToExpectedState() -> controller.enqueueShow(
直接在主线程调用
commitNowAllowingStateLoss
其它
Activity和Fragment的通信方式, Fragment之间如何进行通信
Activity和Fragment
1.采用Bundle的方式 在activity中建一个bundle,把要传的值存入bundle,然后通过fragment的
setArguments(bundle)传到fragment,在fragment中,用getArguments接收。
2.采用接口回调的方式
3.EventBus的方式
4.viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递
Fragment之间
1.EventBus的方式
2.采用接口回调的方式
3.Fragment 通过 getActivity 获取到Activity,Activity通过findFragmentByTag||findFragmentById获取
Fragment,Fragment 实现接口.
为什么使用Fragment.setArguments(Bundle)传递参数
https://www.jianshu.com/p/c06efe090589 Activity.onCreate(Bundle saveInstance)->Fragment.instantitate()
当再次重建时会通过空参构造方法反射出新的fragment。并且给mArgments初始化为原先的值,而原来的
Fragment实例的数据都丢失了。
Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过
Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来,并在重建时恢复。所以,尽量使用
Fragment.setArguments(Bundle bundle)方式来进行参数传递。
FragmentPageAdapter和FragmentStatePageAdapter区别及使用场景
使用FragmentPagerAdapter时页面切换,只是调用detach,而不是remove,所以只执行onDestroyView,而不是onDestroy,不会摧毁Fragment实例,只会摧毁Fragment 的View;
使用FragmentStatePageAdapter时页面切换,调用remove,执行onDestroy。直接摧毁Fragment。
FragmentPagerAdapter最好用在少数静态Fragments的场景,用户访问过的Fragment都会缓存在内存中,即
使其视图层次不可见而被释放(onDestroyView) 。因为Fragment可能保存大量状态,因此这可能会导致使用大量内存。
页面很多时,可以考虑FragmentStatePagerAdapter
fragment懒加载
判断当前 Fragment 是否对用户可见,只是 onHiddenChanged() 是在 add+show+hide 模式下使用,
setUserVisibleHint 是在 ViewPager+Fragment 模式下使用。
老的懒加载处理方案
对 ViewPager 中的 Fragment 懒加载
- 方法1: 继承模式
通过继承懒加载Fragment基类,在setUserVisibleHint中判断可见并且当onViewCreated()表明View已经加载完毕后再掉用加载方法。 - 方法2:代理+反射模式
1.adapter中getitem时new一个代理fragment
2.setUserVisibleHint中根据反射得到真正的fragement
3.通过add commit把真正的fragement添加到代理fragment中
方法1:不可见的 Fragment 执行了 onResume() 方法。因为setUserVisibleHint位于onCreateView之前,此时为false,onResume之后为true,在true后加载相当于onResume()等方法在真实的createView之前调用,不可见的Fragment 执行了 onResume() 方法。
Androidx 下的懒加载
在 FragmentPagerAdapter 与 FragmentStatePagerAdapter 新增了含有 behavior 字段的构造函数如果 behavior 的值为 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT ,那么当前选中的 Fragment 在Lifecycle.State#RESUMED 状态 ,其他不可见的 Fragment 会被限制在 Lifecycle.State#STARTED 状态原因:FragmentPagerAdapter 在其 setPrimaryItem 方法中调用了 setMaxLifecycle, 所以说onResume中执行懒加载
ViewPager2与ViewPager区别
- FragmentStateAdapter 替代FragmentStatePagerAdapter,PagerAdapter被RecyclerView.Adapter替代
- 支持竖直滑动,禁止滑动
- PageTransformer用来设置页面动画,设置页面间距
- 预加载当setOffscreenPageLimit被设置为OFFSCREEN_PAGE_LIMIT_DEFAULT时候会使用RecyclerView的
缓存机制。