Android-Fragment简要分析
注意:文章对Fragment源码的分析基于support v4的Fragment包,版本号为25.3.1
Fragment相关类UML图
1008428-b84d45b1ba19d73d.jpgsupport包中对负责管理Fragment生命是FragmentActivity,v7包的AppCompatActivity也是继承于它。
FragmentActivity管理Fragment是通过它内部mFragments的变量,mFragments类型为FragmentController.
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
FragmentActivity传递自身生命状态、状态保存、恢复都是通过调用mFragments相应的方法进行处理;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
//...
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
//...
mFragments.dispatchCreate();
}
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
而FragmentController本身只是简单的将相应请求转发给FragmentManagerImpl,只是起到了桥梁沟通作用。
FragmentActivity创建mFragments时传递了一个HostCallbacks内部类实例,这个callback对象给Fragment提供了获取Context,启动Activity的能力。
Fragment
Fragment主要是由Attr、View、State构成,
Attr:固有属性,Fragment基本信息,基本不会随生命周期变化。
Bundle mArguments; //构造参数
boolean mFromLayout; //是否从layout文件中创建
String mTag;
...
View:Fragment管理View所依赖的相关成员变量。
// The parent container of the fragment after dynamically added to UI.
ViewGroup mContainer;
// The View generated for this fragment.
View mView;
// The real inner view that will save/restore state.
View mInnerView;
State:Fragment的状态,管理Fragment的显示、生命周期。
int mState = INITIALIZING; //生命周期状态
boolean mAdded; //是否被添加
boolean mRemoving; //是否被移除
boolean mHidden;// 是否被隐藏
boolean mDetached; //是否已经分离
// mState取值如下
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的生命周期方法,onAttach, onCreate, onCreateView...都是在mState状态变化中进行回调的。
Fragment的事务:FragmentTransaction、BackStackRecord
添加一个Fragment,我们一般使用如下代码:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.contaniner, fragment);
transaction.commit();
FragmentTransaction表示一个事务,提供了如add、remove、attach、detach、show、hide、replace等接口操控Fragment。它的具体实现类是BackStackRecord,它的接口实现如下:
@Override
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
...
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}
@Override
public FragmentTransaction remove(Fragment fragment) {
Op op = new Op();
op.cmd = OP_REMOVE;
op.fragment = fragment;
addOp(op);
return this;
}
...
可以看到我们调用的add、remove等方法最后都是生成一个Op对象保存在mOps列表中,Op是Operator简写表示操作,Op的cmd属性则区分操作的类型,cmd的值取如下几种:
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;
上面操作完毕后,最后是commit事务了
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
@Override
public void commitNow() {
...
// 直接开始执行事务
mManager.execSingleAction(this, false);
}
@Override
public void commitNowAllowingStateLoss() {
...
// 直接开始执行事务
mManager.execSingleAction(this, true);
}
int commitInternal(boolean allowStateLoss) {
...
// 事务入对象,等待下一个Handler回调执行
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
*AllowingStateLoss表示是否允许状态丢失,如果不允许但是当前Activity状态已经触发保存了调用会抛出异常;commit、commitNow的区别则是提交事务等待下个主线程Handler回调执行还是立即执行,除了执行时机不一样外,两者最后触发的事务执行逻辑是一样的。
事务执行逻辑依然在BackStackRecord中:
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);
}
}
执行逻辑是遍历所有添加的操作,执行相应的FragmentManage方法,最后将Fragment的状态移动的相应的状态。
Fragment状态变迁:moveToState
Fragment添加到FragmentMange中后,要将它移动到相应的状态,使Fragment正确的显示、交互。
FragmentManage的成员变量mCurState存储着当前Activity状态对应的Fragment状态值,它的取值范围如同Fragment。Activity的状态发生变化时都会触发相应方法修改mCurState,并将所有的active 的Fragment移动到相应的状态上。
public void dispatchCreate() {
mStateSaved = false;
moveToState(Fragment.CREATED, false);
}
public void dispatchActivityCreated() {
mStateSaved = false;
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchStart() {
mStateSaved = false;
moveToState(Fragment.STARTED, false);
}
public void dispatchResume() {
mStateSaved = false;
moveToState(Fragment.RESUMED, false);
}
public void dispatchPause() {
moveToState(Fragment.STARTED, false);
}
public void dispatchStop() {
// See saveAllState() for the explanation of this. We do this for
// all platform versions, to keep our behavior more consistent between
// them.
mStateSaved = true;
moveToState(Fragment.STOPPED, false);
}
public void dispatchReallyStop() {
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mHost = null;
mContainer = null;
mParent = null;
}
FragmentManage的moveToState方法就负责了将自己管理的所有Fragment的状态移动到对应的状态上,当mCurState变化,或者Fragment操作触发都会调用该方法。
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
...
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.
...
switch (f.mState) {
case Fragment.INITIALIZING:
...
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
...
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
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();
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
}
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) {
...
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
...
}
}
}
...
}
fragment的state取值,为前面提到的七中状态,其中最低值是INITIALIZING状态,代表fragment刚创建,还未被add, 最高状态值是RESUMED,代表fragment处于前台。 所以moveToState内部分两条线,状态跃升,和状态降低,里面各有一个switch判断,注意到switch里每个case都没有break,这意味着,状态可以持续变迁,比如从INITIALIZING,一直跃升到RESUMED,将每个case都走一遍,每次case语句内,都会改变state的值。
Untitled.pngFragment状态保存、恢复
主要实现代码是FragmentManageImpl的saveAllState()和restoreAllState()方法。
FragmentActivity的onSaveInstance()方法中会间接调用FragmentManageImpl的saveAllState()方法,而onCreate(Bundle)中会间接调用restoreAllState()。在Fragment的onCreate(Bundle)等初始化生命方法中会传入保存状态的Bundle,以供开发者恢复存储的数据。而Fragment中view的状态的恢复则是在回调了onCreateView()后得到开发者返回的view,手动触发view状态的恢复:
// FragmentManageImpl.class
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
...
if(f.mState < newState) { // 状态升
...
switch(f.mState) {
...
case Fragment.CREATED:
...
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
...
f.performActivityCreated(f.mSavedFragmentState);
...
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
...
}
...
}
// Fragment.class
final void restoreViewState(Bundle savedInstanceState) {
if (mSavedViewState != null) {
mInnerView.restoreHierarchyState(mSavedViewState);
mSavedViewState = null;
}
mCalled = false;
onViewStateRestored(savedInstanceState);
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onViewStateRestored()");
}
}
Fragment常见错误:
可以参考:https://www.jianshu.com/p/d9143a92ad94
getActivity空指针错误
状态没保存、值丢失
Can not perform this action after onSaveInstanceState异常
Fragment类必须提供无参构造方法
Fragment重叠显示异常
其他
Fragment中还有回退栈、动画、Android5.0中的共享元素及Activity动画、Fragment.retainInstance属性、LoaderManager、ChildFragmentManage等知识点这里先不讨论了。