本文主要是介绍(一百三十七)梳理fragment的isAdded,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
1.api
2.流程梳理
2.1 addFragment
2.2 attachFragment
2.3 restoreAllState
3.总结
1.api
/frameworks/base/core/java/android/app/Fragment.java
/*** Return true if the fragment is currently added to its activity.*/final public boolean isAdded() {return mHost != null && mAdded;}
isAdded表示当前fragment有没有被加入到activity,那add具体是指的什么呢?在哪里被设为true?mAdded在fragment中只有初始化
// True if the fragment is in the list of added fragments.boolean mAdded;
由于它是个Default权限的,所有只能是同包或者子类有权修改。
2.流程梳理
那么fragment的mAdded的参数只有是FragmentManager会改,看下具体改动的地方
搜了下有3个方法
- addFragment
- attachFragment
- restoreAllState
2.1 addFragment
public void addFragment(Fragment fragment, boolean moveToStateNow) {if (DEBUG) Log.v(TAG, "add: " + fragment);makeActive(fragment);if (!fragment.mDetached) {if (mAdded.contains(fragment)) {throw new IllegalStateException("Fragment already added: " + fragment);}synchronized (mAdded) {mAdded.add(fragment);}fragment.mAdded = true;fragment.mRemoving = false;if (fragment.mView == null) {fragment.mHiddenChanged = false;}if (fragment.mHasMenu && fragment.mMenuVisible) {mNeedMenuInvalidate = true;}if (moveToStateNow) {moveToState(fragment);}}}
这里可以看到有个mAdded的ArrayList,会将add的fragment加进去,加进去后将fragment的标志位置为true。
final ArrayList<Fragment> mAdded = new ArrayList<>();
接着看下addFragment哪里有调用
@Overridepublic View onCreateView(View parent, String name, Context context, AttributeSet attrs) {if (!"fragment".equals(name)) {return null;}String fname = attrs.getAttributeValue(null, "class");TypedArray a =context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);if (fname == null) {fname = a.getString(com.android.internal.R.styleable.Fragment_name);}int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID);String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);a.recycle();int containerId = parent != null ? parent.getId() : 0;if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {throw new IllegalArgumentException(attrs.getPositionDescription()+ ": Must specify unique android:id, android:tag, or have a parent with"+ " an id for " + fname);}// If we restored from a previous state, we may already have// instantiated this fragment from the state and should use// that instance instead of making a new one.Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;if (fragment == null && tag != null) {fragment = findFragmentByTag(tag);}if (fragment == null && containerId != View.NO_ID) {fragment = findFragmentById(containerId);}if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"+ Integer.toHexString(id) + " fname=" + fname+ " existing=" + fragment);if (fragment == null) {fragment = mContainer.instantiate(context, fname, null);fragment.mFromLayout = true;fragment.mFragmentId = id != 0 ? id : containerId;fragment.mContainerId = containerId;fragment.mTag = tag;fragment.mInLayout = true;fragment.mFragmentManager = this;fragment.mHost = mHost;fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);addFragment(fragment, true);} else if (fragment.mInLayout) {// A fragment already exists and it is not one we restored from// previous state.throw new IllegalArgumentException(attrs.getPositionDescription()+ ": Duplicate id 0x" + Integer.toHexString(id)+ ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)+ " with another fragment for " + fname);} else {// This fragment was retained from a previous instance; get it// going now.fragment.mInLayout = true;fragment.mHost = mHost;// If this fragment is newly instantiated (either right now, or// from last saved state), then give it the attributes to// initialize itself.if (!fragment.mRetaining) {fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);}}// If we haven't finished entering the CREATED state ourselves yet,// push the inflated child fragment along. This will ensureInflatedFragmentView// at the right phase of the lifecycle so that we will have mView populated// for compliant fragments below.if (mCurState < Fragment.CREATED && fragment.mFromLayout) {moveToState(fragment, Fragment.CREATED, 0, 0, false);} else {moveToState(fragment);}if (fragment.mView == null) {throw new IllegalStateException("Fragment " + fname+ " did not create a view.");}if (id != 0) {fragment.mView.setId(id);}if (fragment.mView.getTag() == null) {fragment.mView.setTag(tag);}return fragment.mView;}
看起来是fragment创建的生命周期有调用。
2.2 attachFragment
public void attachFragment(Fragment fragment) {if (DEBUG) Log.v(TAG, "attach: " + fragment);if (fragment.mDetached) {fragment.mDetached = false;if (!fragment.mAdded) {if (mAdded.contains(fragment)) {throw new IllegalStateException("Fragment already added: " + fragment);}if (DEBUG) Log.v(TAG, "add from attach: " + fragment);synchronized (mAdded) {mAdded.add(fragment);}fragment.mAdded = true;if (fragment.mHasMenu && fragment.mMenuVisible) {mNeedMenuInvalidate = true;}}}}
这里也是将fragment加进mAdded中去并将fragment的mAdded设为true,但是不同的是可以fragment.mDetached为true的时候才会attach并且没有added.不同于之前addFragment是fragment.mDetached为false才走进来。
看了下attachFragment是只有如下会调用
/frameworks/base/core/java/android/app/BackStackRecord.java
/*** 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.fragment;if (f != null) {f.setNextTransition(mTransition, mTransitionStyle);}switch (op.cmd) {case OP_ADD:f.setNextAnim(op.enterAnim);mManager.addFragment(f, false);break;case OP_REMOVE:f.setNextAnim(op.exitAnim);mManager.removeFragment(f);break;case OP_HIDE:f.setNextAnim(op.exitAnim);mManager.hideFragment(f);break;case OP_SHOW:f.setNextAnim(op.enterAnim);mManager.showFragment(f);break;case OP_DETACH:f.setNextAnim(op.exitAnim);mManager.detachFragment(f);break;case OP_ATTACH:f.setNextAnim(op.enterAnim);mManager.attachFragment(f);break;
还有个逆过程
/*** Reverses the execution of the operations within this transaction. The Fragment states will* only be modified if reordering is not allowed.** @param moveToState {@code true} if added fragments should be moved to their final state* in ordered transactions*/void executePopOps(boolean moveToState) {for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {final Op op = mOps.get(opNum);Fragment f = op.fragment;if (f != null) {f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),mTransitionStyle);}switch (op.cmd) {case OP_ADD:f.setNextAnim(op.popExitAnim);mManager.removeFragment(f);break;case OP_REMOVE:f.setNextAnim(op.popEnterAnim);mManager.addFragment(f, false);break;case OP_HIDE:f.setNextAnim(op.popEnterAnim);mManager.showFragment(f);break;case OP_SHOW:f.setNextAnim(op.popExitAnim);mManager.hideFragment(f);break;case OP_DETACH:f.setNextAnim(op.popEnterAnim);mManager.attachFragment(f);break;case OP_ATTACH:f.setNextAnim(op.popExitAnim);mManager.detachFragment(f);break;
看下OP_ATTCH是怎么加进去的
public FragmentTransaction attach(Fragment fragment) {addOp(new Op(OP_ATTACH, fragment));return this;}void addOp(Op op) {mOps.add(op);op.enterAnim = mEnterAnim;op.exitAnim = mExitAnim;op.popEnterAnim = mPopEnterAnim;op.popExitAnim = mPopExitAnim;}
流程理不顺了,后续打个堆栈看下。
2.3 restoreAllState
restoreAllState看起来是个恢复机制
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {// If there is no saved state at all, then there can not be// any nonConfig fragments either, so that is that.if (state == null) return;FragmentManagerState fms = (FragmentManagerState)state;if (fms.mActive == null) return;List<FragmentManagerNonConfig> childNonConfigs = null;// First re-attach any non-config instances we are retaining back// to their saved state, so we don't try to instantiate them again.if (nonConfig != null) {List<Fragment> nonConfigFragments = nonConfig.getFragments();childNonConfigs = nonConfig.getChildNonConfigs();final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;for (int i = 0; i < count; i++) {Fragment f = nonConfigFragments.get(i);if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);int index = 0; // index of f in fms.mActivewhile (index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex) {index++;}if (index == fms.mActive.length) {throwException(new IllegalStateException("Could not find active fragment "+ "with index " + f.mIndex));}FragmentState fs = fms.mActive[index];fs.mInstance = f;f.mSavedViewState = null;f.mBackStackNesting = 0;f.mInLayout = false;f.mAdded = false;f.mTarget = null;if (fs.mSavedFragmentState != null) {fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(FragmentManagerImpl.VIEW_STATE_TAG);f.mSavedFragmentState = fs.mSavedFragmentState;}}}// Build the full list of active fragments, instantiating them from// their saved state.mActive = new SparseArray<>(fms.mActive.length);for (int i=0; i<fms.mActive.length; i++) {FragmentState fs = fms.mActive[i];if (fs != null) {FragmentManagerNonConfig childNonConfig = null;if (childNonConfigs != null && i < childNonConfigs.size()) {childNonConfig = childNonConfigs.get(i);}Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);mActive.put(f.mIndex, f);// Now that the fragment is instantiated (or came from being// retained above), clear mInstance in case we end up re-restoring// from this FragmentState again.fs.mInstance = null;}}// Update the target of all retained fragments.if (nonConfig != null) {List<Fragment> nonConfigFragments = nonConfig.getFragments();final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;for (int i = 0; i < count; i++) {Fragment f = nonConfigFragments.get(i);if (f.mTargetIndex >= 0) {f.mTarget = mActive.get(f.mTargetIndex);if (f.mTarget == null) {Log.w(TAG, "Re-attaching retained fragment " + f+ " target no longer exists: " + f.mTargetIndex);f.mTarget = null;}}}}// Build the list of currently added fragments.mAdded.clear();if (fms.mAdded != null) {for (int i=0; i<fms.mAdded.length; i++) {Fragment f = mActive.get(fms.mAdded[i]);if (f == null) {throwException(new IllegalStateException("No instantiated fragment for index #" + fms.mAdded[i]));}f.mAdded = true;if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);if (mAdded.contains(f)) {throw new IllegalStateException("Already added!");}synchronized (mAdded) {mAdded.add(f);}}}// Build the back stack.if (fms.mBackStack != null) {mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);for (int i=0; i<fms.mBackStack.length; i++) {BackStackRecord bse = fms.mBackStack[i].instantiate(this);if (DEBUG) {Log.v(TAG, "restoreAllState: back stack #" + i+ " (index " + bse.mIndex + "): " + bse);LogWriter logw = new LogWriter(Log.VERBOSE, TAG);PrintWriter pw = new FastPrintWriter(logw, false, 1024);bse.dump(" ", pw, false);pw.flush();}mBackStack.add(bse);if (bse.mIndex >= 0) {setBackStackIndex(bse.mIndex, bse);}}} else {mBackStack = null;}if (fms.mPrimaryNavActiveIndex >= 0) {mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);}mNextFragmentIndex = fms.mNextFragmentIndex;}
其中和added相关的就是将缓存的mAdded集合中的fragment清空,从state中重新获取加入
FragmentManagerState fms = (FragmentManagerState)state;
... // Build the list of currently added fragments.mAdded.clear();if (fms.mAdded != null) {for (int i=0; i<fms.mAdded.length; i++) {Fragment f = mActive.get(fms.mAdded[i]);if (f == null) {throwException(new IllegalStateException("No instantiated fragment for index #" + fms.mAdded[i]));}f.mAdded = true;if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);if (mAdded.contains(f)) {throw new IllegalStateException("Already added!");}synchronized (mAdded) {mAdded.add(f);}}}
3.总结
本地梳理只是粗浅的找了下大概代码位置,待后续打印堆栈继续梳理。
FragmentManager共有3个方法会将isAdded变为true
- addFragment
- attachFragment
- restoreAllState
这篇关于(一百三十七)梳理fragment的isAdded的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!