//移除一个已经存在的 fragment
//如果之前添加到宿主上,那它的布局也会被移除
public abstract FragmentTransaction remove(Fragment fragment);
//隐藏一个已存的 fragment
//其实就是将添加到宿主上的布局隐藏
public abstract FragmentTransaction hide(Fragment fragment);
//显示前面隐藏的 fragment,这只适用于之前添加到宿主上的 fragment
public abstract FragmentTransaction show(Fragment fragment);
//将指定的 fragment 将布局上解除
//当调用这个方法时,fragment 的布局已经销毁了
public abstract FragmentTransaction detach(Fragment fragment);
//当前面解除一个 fragment 的布局绑定后,调用这个方法可以重新绑定
//这将导致该 fragment 的布局重建,然后添加、展示到界面上
public abstract FragmentTransaction attach(Fragment fragment);
对 fragment 的操作基本就这几步,我们知道,要完成对 fragment 的操作,最后还需要提交一下:
mFragmentManager.beginTransaction()
.replace(R.id.fl_child, getChildFragment())
// .commit()
.commitAllowingStateLoss();
事务的四种提交方式
事务最终的提交方法有四种:
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()
它们之间的特点及区别如下:
public abstract int commit();
commit()
在主线程中异步执行,其实也是 Handler 抛出任务,等待主线程调度执行。
注意:
commit()
需要在宿主 Activity 保存状态之前调用,否则会报错。
这是因为如果 Activity 出现异常需要恢复状态,在保存状态之后的commit()
将会丢失,这和调用的初衷不符,所以会报错。
public abstract int commitAllowingStateLoss();
commitAllowingStateLoss()
也是异步执行,但它的不同之处在于,允许在 Activity 保存状态之后调用,也就是说它遇到状态丢失不会报错。
因此我们一般在界面状态出错是可以接受的情况下使用它。
public abstract void commitNow();
commitNow()
是同步执行的,立即提交任务。
前面提到 FragmentManager.executePendingTransactions()
也可以实现立即提交事务。但我们一般建议使用 commitNow()
, 因为另外那位是一下子执行所有待执行的任务,可能会把当前所有的事务都一下子执行了,这有可能有副作用。
此外,这个方法提交的事务可能不会被添加到 FragmentManger 的后退栈,因为你这样直接提交,有可能影响其他异步执行任务在栈中的顺序。
和 commit()
一样,commitNow()
也必须在 Activity 保存状态前调用,否则会抛异常。
public abstract void commitNowAllowingStateLoss();
同步执行的 commitAllowingStateLoss()
。
OK,了解了 FragmentTransaction
定义的操作,去看看我们真正关心的、 beginTransaction()
中返回的 BackStackRecord
:
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
事务真正实现/回退栈 BackStackRecord
BackStackRecord
既是对 Fragment 进行操作的事务的真正实现,也是 FragmentManager 中的回退栈的实现:
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {…}
它的关键成员:
final FragmentManagerImpl mManager;
//Op 可选的状态值
static final int OP_NULL = 0;
static final int OP_ADD = 1;
static final int OP_REPLACE = 2;
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
ArrayList mOps = new ArrayList<>();
static final class Op {
int cmd; //状态
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
}
int mIndex = -1; //栈中最后一个元素的索引
可以看到 Op 就是添加了状态和动画信息的 Fragment, mOps
就是栈中所有的 Fragment。
事务定义的方法它是如何实现的呢。
先看添加一个 Fragment 到布局 add()
的实现:
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, 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.");
}
//1.修改添加的 fragmentManager 为当前栈的 manager
fragment.mFragmentManager = mManager;
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);
}
//2.设置宿主 ID 为布局 ID
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
//3.构造 Op
Op op = new Op();
op.cmd = opcmd; //状态
op.fragment = fragment;
//4.添加到数组列表中
addOp(op);
}
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}
可以看到添加一个 Fragment 到布局很简单,概况一下就是:
修改 fragmentManager 和 ID,构造成 Op,设置状态信息,然后添加到列表里。
添加完了看看替换 replace
的实现:
@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
return replace(containerViewId, fragment, null);
}
@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException(“Must use non-zero containerViewId”);
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
太可怕了,也是调用上面刚提到的 doAddOp()
,不同之处在于第四个参数为 OP_REPLACE
,看来之前小看了这个状态值!
再看其他方法的实现就很简单了,无非就是构造一个 Op,设置对应的状态值。
@Override
public FragmentTransaction remove(Fragment fragment) {
Op op = new Op();
op.cmd = OP_REMOVE;
op.fragment = fragment;
addOp(op);
return this;
}
@Override
public FragmentTransaction hide(Fragment fragment) {
Op op = new Op();
op.cmd = OP_HIDE;
op.fragment = fragment;
addOp(op);
return this;
}
@Override
public FragmentTransaction show(Fragment fragment) {
Op op = new Op();
op.cmd = OP_SHOW;
op.fragment = fragment;
addOp(op);
return this;
}
那这些状态值的不同是什么时候起作用的呢?
别忘了我们操作 Fragment 还有最后一步,提交。
看看这两个是怎么实现的:
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException(“commit already called”);
//…
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this); //更新 index 信息
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss); //异步任务入队
return mIndex;
}
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
throw new IllegalStateException(“Activity has been destroyed”);
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit(); //发送任务
}
}
private void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
前面已经介绍过了,FragmentManager.enqueueAction()
最终是使用 Handler 实现的异步执行。
现在的问题是执行的任务是啥?
答案就是 Handler 发送的任务 mExecCommit
:
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
/**
- Only call from main thread!
- 更新 UI 嘛,肯定得在主线程
*/
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
optimizeAndExecuteOps(mTmpRecords, mTmpIsPop); //这里是入口
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
return didSomething;
}
private void optimizeAndExecuteOps(ArrayList records,
ArrayList isRecordPop) {
if (records == null || records.isEmpty()) {
return;
}
if (isRecordPop == null || 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 canOptimize = records.get(recordNum).mAllowOptimization;
if (!canOptimize) {
// execute all previous transactions
if (startIndex != recordNum) {
//这里将 Ops 过滤一遍
executeOpsTogether(records, isRecordPop, startIndex, recordNum);
}
// execute all unoptimized pop operations together or one add operation
//…
}
if (startIndex != numRecords) {
executeOpsTogether(records, isRecordPop, startIndex, numRecords);
}
}
private void executeOpsTogether(ArrayList records,
ArrayList isRecordPop, int startIndex, int endIndex) {
final boolean allowOptimization = records.get(startIndex).mAllowOptimization;
boolean addToBackStack = false;
if (mTmpAddedFragments == null) {
mTmpAddedFragments = new ArrayList<>();
} else {
mTmpAddedFragments.clear();
}
if (mAdded != null) {
mTmpAddedFragments.addAll(mAdded);
}
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
final BackStackRecord record = records.get(recordNum);
final boolean isPop = isRecordPop.get(recordNum);
if (!isPop) {
record.expandReplaceOps(mTmpAddedFragments); //修改状态
} else {
record.trackAddedFragmentsInPop(mTmpAddedFragments);
}
addToBackStack = addToBackStack || record.mAddToBackStack;
}
mTmpAddedFragments.clear();
if (!allowOptimization) {
FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
false);
}
//真正处理的入口
executeOps(records, isRecordPop, startIndex, endIndex);
int postponeIndex = endIndex;
if (allowOptimization) {
ArraySet addedFragments = new ArraySet<>();
addAddedFragments(addedFragments);
postponeIndex = postponePostponableTransactions(records, isRecordPop,
startIndex, endIndex, addedFragments);
makeRemovedFragmentsInvisible(addedFragments); //名字就能看出来作用
}
if (postponeIndex != startIndex && allowOptimization) {
// need to run something now
FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
postponeIndex, true);
moveToState(mCurState, true);
}
//…
}
//修改 Ops 状态,这一步还没有真正处理状态
expandReplaceOps(ArrayList added) {
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.fragment);
break;
case OP_REMOVE:
case OP_DETACH:
added.remove(op.fragment);
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i–) {
Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
Op removeOp = new Op();
removeOp.cmd = OP_REMOVE; //可以看到,替换也是通过删除实现的
removeOp.fragment = old;
removeOp.enterAnim = op.enterAnim;
removeOp.popEnterAnim = op.popEnterAnim;
removeOp.exitAnim = op.exitAnim;
removeOp.popExitAnim = op.popExitAnim;
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum–;
} else {
op.cmd = OP_ADD;
added.add(f);
}
}
break;
}
}
}
//设置将要被移除的 Fragment 为不可见的最终实现
private void makeRemovedFragmentsInvisible(ArraySet fragments) {
final int numAdded = fragments.size();
for (int i = 0; i < numAdded; i++) {
final Fragment fragment = fragments.valueAt(i);
if (!fragment.mAdded) {
final View view = fragment.getView(); //获取 Fragment 的布局,设置状态
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
fragment.getView().setVisibility(View.INVISIBLE);
} else { //高版本设置透明度
fragment.mPostponedAlpha = view.getAlpha();
view.setAlpha(0f);
}
}
}
}
代码多了一点,但我们终于找到了最终的实现:Handler 异步发到主线,调度执行后,聚合、修改 Ops 的状态,然后遍历、修改 Fragment 栈中的 View 的状态。
真正处理的部分
前面主要是对 Fragment 的包装类 Ops 进行一些状态修改,真正根据 Ops 状态进行操作在这个部分:
/**
- 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;
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;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
if (!mAllowOptimization && op.cmd != OP_ADD) {
mManager.moveFragmentToExpectedState(f);
}
}
if (!mAllowOptimization) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}
FragmentManager 对这些方法的实现也很简单,修改 Fragment 的状态值,比如 remove(Fragment)
:
public void removeFragment(Fragment fragment) {
if (DEBUG) Log.v(TAG, “remove: " + fragment + " nesting=” + fragment.mBackStackNesting);
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
if (mAdded != null) {
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false; //设置属性值
fragment.mRemoving = true;
}
}
最终会调用 moveToState()
,我们直接来看它的实现:
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//还没有添加的 Fragment 处于 onCreate() 状态
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
// While removing a fragment, we can’t change it to a higher state.
newState = f.mState;
}
//推迟启动的设置为 stop
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState < newState) {
// For fragments that are created from a layout, when restoring from
// state we don’t want to allow them to be created until they are
// being reloaded from the layout.
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.getAnimatingAway() != null) {
// The fragment is currently being animated… but! Now we
// want to move our state back up. Give up on waiting for the
// animation, move to whatever the final state should be once
// the animation is done, and then we can proceed from there.
f.setAnimatingAway(null);
//如果当前 Fragment 正有动画,直接修改为最终状态
moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
}
switch (f.mState) {
case Fragment.INITIALIZING:
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mTarget = getFragment(f.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG);
if (f.mTarget != null) {
f.mTargetRequestCode = f.mSavedFragmentState.getInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
}
f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
if (!f.mUserVisibleHint) {
f.mDeferStart = true;
if (newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
}
}
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext()); //调用 Fragment 生命周期方法
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
- " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState); //调用 Fragment 生命周期方法
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState);
f.mState = Fragment.CREATED;
}
f.mRetaining = false;
if (f.mFromLayout) { //从布局解析来的
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
f.mView = f.performCreateView(f.getLayoutInflater( //调用 Fragment 生命周期方法
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState); //调用 Fragment 生命周期方法
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
} else {
f.mInnerView = null;
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(
"Cannot create fragment "
- f
- " for a container view with no id"));
}
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
} catch (NotFoundException e) {
resName = “unknown”;
}
throwException(new IllegalArgumentException(
“No view found for id 0x” - Integer.toHexString(f.mContainerId) + " ("
- resName
- ") for fragment " + f));
}
}
f.mContainer = container;
f.mView = f.performCreateView(f.getLayoutInflater( //调用 Fragment 生命周期方法
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (container != null) {
container.addView(f.mView); //将 Fragment 的布局添加到父布局中
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
f.onViewCreated(f.mView, f.mSavedFragmentState);//调用 Fragment 生命周期方法
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
// Only animate the view if it is visible. This is done after
// dispatchOnFragmentViewCreated in case visibility is changed
f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
&& f.mContainer != null;
} else {
f.mInnerView = null;
}
}
f.performActivityCreated(f.mSavedFragmentState); //调用 Fragment 生命周期方法
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED) {
f.mState = Fragment.STOPPED;
}
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
dispatchOnFragmentStarted(f, false);
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
dispatchOnFragmentResumed(f, false);
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
f.performPause();
dispatchOnFragmentPaused(f, false);
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
dispatchOnFragmentStopped(f, false);
}
case Fragment.STOPPED:
if (newState < Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
f.performReallyStop();
}
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
saveFragmentViewState(f);
}
}
f.performDestroyView();
dispatchOnFragmentViewDestroyed(f, false);
if (f.mView != null && f.mContainer != null) {
Animation anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
&& f.mPostponedAlpha >= 0) {
anim = loadAnimation(f, transit, false,
transitionStyle);
}
f.mPostponedAlpha = 0;
if (anim != null) {
final Fragment fragment = f;
f.setAnimatingAway(f.mView);
f.setStateAfterAnimating(newState);
final View viewToAnimate = f.mView;
anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(
viewToAnimate, anim) {
@Override
public void onAnimationEnd(Animation animation) {
super.onAnimationEnd(animation);
if (fragment.getAnimatingAway() != null) {
fragment.setAnimatingAway(null);
moveToState(fragment, fragment.getStateAfterAnimating(),
0, 0, false);
}
}
});
f.mView.startAnimation(anim);
}
f.mContainer.removeView(f.mView);
}
f.mContainer = null;
f.mView = null;
f.mInnerView = null;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (mDestroyed) {
if (f.getAnimatingAway() != null) {
// The fragment’s containing activity is
// being destroyed, but this fragment is
// currently animating away. Stop the
// animation right now – it is not needed,
// and we can’t wait any more on destroying
// the fragment.
View v = f.getAnimatingAway();
f.setAnimatingAway(null);
v.clearAnimation();
}
}
if (f.getAnimatingAway() != null) {
// We are waiting for the fragment’s view to finish
// animating away. Just make a note of the state
// the fragment now should move to once the animation
// is done.
f.setStateAfterAnimating(newState);
newState = Fragment.CREATED;
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
f.performDestroy();
dispatchOnFragmentDestroyed(f, false);
} else {
f.mState = Fragment.INITIALIZING;
}
f.performDetach();
dispatchOnFragmentDetached(f, false);
if (!keepActive) {
if (!f.mRetaining) {
makeInactive(f);
} else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
}
}
}
}
}
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
- "expected state " + newState + " found " + f.mState);
f.mState = newState;
}
}
代码很长,但做的事情很简单:
- 根据状态调用对应的生命周期方法
- 如果是新创建的,就把布局添加到 ViewGroup 中
Fragment 是什么
Fragment 是什么,从官网、别人博客上看到的都是他人之言,我们还是得去看源码才能得到答案。
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {…}
可以看到,Fragment 没有继承任何类,只是实现了这两个接口,第二个不太重要,第一个是在内存不足时可以收到回调。
没有什么特别信息,我们还是去看看它的主要成员。
Fragment 的主要成员
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
//当前 Fragment 的状态值
int mState = INITIALIZING;
//…
// True if the fragment is in the list of added fragments.
boolean mAdded;
// If set this fragment is being removed from its activity.
boolean mRemoving;
// Set to true if this fragment was instantiated from a layout file.
boolean mFromLayout;
// Set to true when the view has actually been inflated in its layout.
boolean mInLayout;
// True if this fragment has been restored from previously saved state.
boolean mRestored;
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
// Set to true when the app has requested that this fragment be hidden
// from the user.
boolean mHidden;
// Set to true when the app has requested that this fragment be deactivated.
boolean mDetached;
// If set this fragment would like its instance retained across
// configuration changes.
boolean mRetainInstance;
// If set this fragment is being retained across the current config change.
boolean mRetaining;
// If set this fragment has menu items to contribute.
boolean mHasMenu;
// Set to true to allow the fragment’s menu to be shown.
boolean mMenuVisible = true;
// Used to verify that subclasses call through to super class.
boolean mCalled;
一堆标志位和状态值。然后就是关键的成员了:
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManagerImpl mFragmentManager;
//Fragmemt 绑定的对象,一半就是 Activity 和 Fragment
FragmentHostCallback mHost;
//管理子 Fragment
FragmentManagerImpl mChildFragmentManager;
// For use when restoring fragment state and descendant fragments are retained.
// This state is set by FragmentState.instantiate and cleared in onCreate.
FragmentManagerNonConfig mChildNonConfig;
//如果这个 Fragment 绑定的是另一个 Fragment,就需要设置这个值
Fragment mParentFragment;
//容器 Fragment 的ID
int mFragmentId;
//容器 View 的ID
int mContainerId;
//父布局
ViewGroup mContainer;
//当前 Fragment 的布局
View mView;
//真正保存状态的内部布局
View mInnerView;
看到这里,结合前面的,我们就清晰了一个 Fragment 的创建、添加过程:
在 onCreateView()
中返回一个 布局,然后在 FragmentManager 中拿到这个布局,添加到要绑定容器(Activity/Fragment)的 ViewGroup 中,然后设置相应的状态值。
生命周期方法
Fragment 的生命周期大家都清楚,官方提供了一张很清晰的图:
总共 11 个方法,这里我们看一下各个方法的具体源码。
1. onAttach(Context)
@CallSuper
public void onAttach(Context context) {
mCalled = true;
final Activity hostActivity = mHost == null ? null : mHost.getActivity();
if (hostActivity != null) {
mCalled = false;
onAttach(hostActivity);
}
}
@Deprecated
@CallSuper
public void onAttach(Activity activity) {
mCalled = true;
}
onAttach()
是一个 Fragment 和它的 Context 关联时第一个调用的方法,这里我们可以获得对应的 Context
或者 Activity
,可以看到这里拿到的 Activity 是 mHost.getActivity()
,后面我们介绍 FragmentManager 时介绍这个方法。
2. onCreate(Bundle)
public void onCreate(@Nullable Bundle savedInstanceState) {
mCalled = true;
restoreChildFragmentState(savedInstanceState);
if (mChildFragmentManager != null
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
题外话
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊
这里我为大家准备了一些我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
欢迎评论区讨论。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!*
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-bPfB6M6g-1711912752186)]
[外链图片转存中…(img-XJNsovYW-1711912752186)]
[外链图片转存中…(img-i5MJZo0E-1711912752187)]
[外链图片转存中…(img-8AOtV4lZ-1711912752187)]
[外链图片转存中…(img-comu515n-1711912752188)]
[外链图片转存中…(img-5KkNZBFq-1711912752188)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-OSJZokrH-1711912752189)]
题外话
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊
这里我为大家准备了一些我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
[外链图片转存中…(img-u2Fgf83y-1711912752189)]
欢迎评论区讨论。