Fragment深入学习
本节将对Fragment进行学习和探究,了解底层原理。通过一个简单的使用范例为入口,层层深入最终分析出FragmentActivity、FragmentTransaction、FragmentManager类之间方法如何调用,对象如何创建,Fragment生命周期如何实现等等问题。通过具体的分析得出结论如下:
- 在FragmentManager中存在多个moveToState方法,按照参数类型个人将其分两类,一类是参数中有Fragment的moveToState方法,另一类自然就是参数中无Fragment的moveToState方法。第一类是针对一个特定的Fragment进行操作,主要工作就是将指定的Fragment状态转移到FragmentManager的mCurState状态。第二类就是更新FragmentManager的mCurState状态!
- Fragment状态分为Initial、Created、ActivityCreated、Stopped、Start、Resume共6个状态。预期状态(newState)大于Fragment自身的状态(f.mState < newState)则将Fragment的状态向前推进对应Fragment的创建过程;预期状态(newState)小于Fragment自身的状态(f.mState > newState)则将Fragment的状态向后推进对应Fragment的销毁过程。
- 不带Fragment参数的moveToSate方法是将FragmentManager下面的所有Fragment状态转移到当前FragmentManager的状态,该方法内部会调用带Fragment参数的moveToState方法。FragmentActivity会间接的调用不带Fragment参数的moveToState方法主要是用于设置当前的FragmentManager的状态。
- 带Fragment参数的moveToState方法是将参数中的Fragment状态转移到当前FragmentManager的状态。FragmentManager的detachFragment、attachFragment、removeFragment、addFragment等方法不会在FragmentActivity中出现,但是会在FragmentTransaction中的run方法中出现,表明每次提交的事务最终会通过调用这些方法完成实际的Fragment的加载与销毁。
一个布局中嵌套多个Fragment范例(平板电脑)##
创建Fragment###
一、ItemsListFragment布局文件
res/layout/fragment_items_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/lvItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</ListView>
</RelativeLayout>
一、ItemsListFragment对象文件
public class ItemsListFragment extends Fragment {
private ArrayAdapter<Item> adapterItems; //Item是自定义的一类数据
private ListView lvItems;
private OnListItemSelectedListener listener;
public interface OnListItemSelectedListener { public void onItemSelected(Item item); }
//自定义接口,用于回调实现该接口的Activity相关方法
@Override public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof OnListItemSelectedListener) {
listener = (OnListItemSelectedListener) activity;
} else {
throw new ClassCastException(
activity.toString() + " must implement ItemsListFragment.OnListItemSelectedListener");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<Item> items = Item.getItems();
adapterItems = new ArrayAdapter<Item>(getActivity(), android.R.layout.simple_list_item_activated_1, items);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_items_list, container, false);
lvItems = (ListView) view.findViewById(R.id.lvItems);
lvItems.setAdapter(adapterItems);
lvItems.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View item, int position, long rowId) {
Item item = adapterItems.getItem(position);
listener.onItemSelected(item);
}
});
return view;
}
public void setActivateOnItemClick(boolean activateOnItemClick) {
lvItems.setChoiceMode(
activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
}
二、ItemDetailFragment布局文件
res/layout/fragment_item_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Item Title"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvTitle"
android:layout_centerHorizontal="true"
android:layout_marginTop="19dp"
android:text="Item Body" />
</RelativeLayout>
二、ItemDetailFragment对象文件
public class ItemDetailFragment extends Fragment {
private Item item;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
item = (Item) getArguments().getSerializable("item"); //之前通过调用Fragment的setArguments方法传进来的bundle数据
}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_item_detail, container, false);
TextView tvTitle = (TextView) view.findViewById(R.id.tvTitle);
TextView tvBody = (TextView) view.findViewById(R.id.tvBody);
tvTitle.setText(item.getTitle());
tvBody.setText(item.getBody());
return view;
}
public static ItemDetailFragment newInstance(Item item) {
ItemDetailFragment fragmentDemo = new ItemDetailFragment();
Bundle args = new Bundle();
args.putSerializable("item", item);
fragmentDemo.setArguments(args); //getArguments().getSerializable("item")获取该数据
return fragmentDemo;
}
}
创建Activity的布局文件activity_items_list.xml###
一、在layout目录下添加一个activity_items_list布局文件
res/layout/activity_items_list.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ItemsListActivity" >
<fragment
android:id="@+id/fragmentItemsList"
android:name="com.codepath.example.masterdetaildemo.ItemsListFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
tools:layout="@layout/fragment_items_list" />
</RelativeLayout>
二、在layout-large目录下添加一个同名activity_items_list布局文件(方法如下)
1.png 3.png<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:showDividers="middle"
android:baselineAligned="false"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/fragmentItemsList"
android:name="com.codepath.example.masterdetaildemo.ItemsListFragment"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_items_list" />
<View android:background="#000000"
android:layout_width="1dp"
android:layout_height="wrap_content"
/>
<FrameLayout
android:id="@+id/flDetailContainer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
</LinearLayout>
<fragment/>标签用于静态的在Activity中嵌入Fragment,通过getSupportFragmentManager() .findFragmentById(R.id.fragmentItemsList)可以获得该ItemsListFragment对象
<FrameLayout/>标签用于动态的在Activity中嵌入Fragment,通过ItemDetailFragment fragmentItem = ItemDetailFragment.newInstance(item); getSupportFragmentManager().beginTransaction().replace(R.id.flDetailContainer, fragmentItem).commit();来动态的显示创建的fragmentItem对象。
上面工作完成后我们就有了res/layout-large/activity_items_list.xml和res/layout/ activity_items_list.xml两个同名文件,系统会根据当前设备屏幕情况使用不同的布局文件。如在平板中使用layout-large/activity_items_list.xml,在普通手机中使用layout/activity_items_list.xml。对于该部分感兴趣的同学可以参考博客http://blog.csdn.net/flowingflying/article/details/6631132
创建Activity对象文件###
public class ItemsListActivity extends AppCompatActivity implements OnItemSelectedListener {
private boolean isTwoPane = false; //平板标志位
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_items_list);
determinePaneLayout(); //判断当前使用的是哪个Layout文件
}
private void determinePaneLayout() {
FrameLayout fragmentItemDetail = (FrameLayout) findViewById(R.id.flDetailContainer); //能够获取到FrameLayout表明使用的平板布局
if (fragmentItemDetail != null) {
isTwoPane = true;
ItemsListFragment fragmentItemsList = (ItemsListFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragmentItemsList);
//因为ItemsListFragment实在平板布局文件中写死的因此可以直接获取到该Fragment,而不需要使用事务(FragmentTransaction)
fragmentItemsList.setActivateOnItemClick(true);
}
}
@Override public void onItemSelected(Item item) {
if (isTwoPane) {
ItemDetailFragment fragmentItem = ItemDetailFragment.newInstance(item);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.flDetailContainer, fragmentItem);
ft.commit();
} else {
Intent i = new Intent(this, ItemDetailActivity.class);
i.putExtra("item", item);
startActivity(i);
}
}
}
创建适用于普通手机屏幕的ItemDetailActivity和对应的布局文件###
public class ItemDetailActivity extends AppCompatActivity {
ItemDetailFragment fragmentItemDetail;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
Item item = (Item) getIntent().getSerializableExtra("item");
if (savedInstanceState == null) {
fragmentItemDetail = ItemDetailFragment.newInstance(item);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.flDetailContainer, fragmentItemDetail);
ft.commit();
}
}
}
res/layout/activity_item_detail.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/flDetailContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ItemDetailActivity" >
</FrameLayout>
上述代码实现了大体如下的功能:
更多资料参考:https://guides.codepath.com/android/Creating-and-Using-Fragments
源码分析##
下面的分析是以getSupportFragmentManager().beginTransaction().add(R.id. flContainer, new DemoFragment(), "SOMETAG").commit();为入口一步步分析得出的。注意getSupportFragmentManager()方法只有在FragmentActivity或者其子类中调用才有效,该方法返回一个FragmentManager对象。下面我们首先从FragmentActivity的getSupportFragmentManager()方法入手
FragmentActivity.class###
Fields####
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
getSupportFragmentManager()@FragmentActivity.class
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
onCreate()@FragmentActivity.class####
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
//该方法其最终目的实则是为了将FragmentController中的HostCallback对象引用传给FragmentManager,具体分析看FragmentController
super.onCreate(savedInstanceState);
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) { mFragments.restoreLoaderNonConfig(nc.loaders); }
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
mFragments.dispatchCreate();
//该方法最底层会调用FragmentManager的同名方法,对具体的Fragment进行操作
}
onSaveInstanceState()@FragmentActivity.class####
@Override protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p); //存储当前Fragment保存的FragmentController的状态
}
}
FragmentActivity的对于Fragment的所有操作都是通过FragmentController进行的。该类很简单,具体下面会分析。FragmentActivity会在当前Activity创建时从Bundle中尝试获取上次关闭的FragmentManager状态,会在当前Activity销毁时将当前FragmentManager的状态存储下来。
FragmentController.class###
Fields####
private final FragmentHostCallback<?> mHost;
createController()@FragmentController.class####
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
FragmentController构造器只接受一个FragmentHostCallback对象,其后的所有操作都是通过它来完成的。比如下面几个常见的方法
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController( mHost, mHost /*container*/, parent);
}
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}
通过上面的几个方法举例,很容易得出结论。FragmentController的方法底层要么是调用FragmentHostCallback的方法,要么就调用FragmentHostCallback的FragmentManager域的方法完成具体的操作。往下我们就来分析一下FragmentHostCallback对象内部结构。
HostCallbacks.class@FragmentActivity.class
class HostCallbacks extends FragmentHostCallback<FragmentActivity>
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
HostCallbacks是一个继承自FragmentHostCallback的类,定义在FragmentActivity内部。不过大部分我们感兴趣的方法都是定义在FragmentHostCallback类中,继续往下看
FragmentHostCallback.class###
Fields####
private final Activity mActivity;
final Context mContext;
private final Handler mHandler;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentHostCallback()@FragmentHostCallback.class####
FragmentHostCallback(FragmentActivity activity) {
this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
FragmentHostCallback(Activity activity, Context context, Handler handler, int windowAnimations) {
mActivity = activity;
mContext = context;
mHandler = handler;
mWindowAnimations = windowAnimations;
}
构造器完成对域中Activity、Handler、FragmentManager的创建初始化。
getFragmentManagerImpl()@FragmentHostCallback.class####
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
到此我们对于getSupportFragmentManager()方法的分析到此结束,分析过程中可以很明显的发现FragmentController中有一个FragmentHostCallback对象,而FragmentHostCallback对象内部拥有当前Activity的context、Handler和一个FragmentManagerImpl对象。FragmentActivity是直接对FragmentController对象进行操作的,而FragmentController底层又是利用FragmentHostCallback对象或者FragmentHostCallback对象的FragmentManager对象完成实际的操作,FragmentManager负责具体的Fragment的创建销毁生命周期的实现。因此下面我们就来好好分析一下FragmentManager类的底层实现。具体分析流程为Fragment、FragmentTransaction、FragmentManager。
Fragment.class###
public class Fragment implements ComponentCallbacks, OnCreateContextMen uListener
Fields####
static final Object USE_DEFAULT_TRANSITION = new Object();
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.
int mState = INITIALIZING;
int mContainerId; //当前Fragment所属的ViewGroup对应的id号
ViewGroup mContainer;
View mView;
View mInnerView;
String mTag; //当前Fragment的标签
Fragment mParentFragment;
FragmentManagerImpl mChildFragmentManager;
FragmentManagerImpl mFragmentManager;
boolean mFromLayout; //当前Fragment来自于一个Layout
boolean mInLayout; //view has actually been inflated in its layout
boolean mResumed;
boolean mDetached; //当前Fragment是否和context已经绑定
boolean mAdded; //当前Fragment是否被存储在FragmentManager的mAdded集合集合中
boolean mRemoving; //当前Fragment已经存在FragmentManager中则该值为false
void initState() {
mIndex = -1;
mWho = null;
mAdded = false;
mRemoving = false;
mResumed = false;
mFromLayout = false;
mInLayout = false;
mRestored = false;
mBackStackNesting = 0;
mFragmentManager = null;
mChildFragmentManager = null;
mHost = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
mHidden = false;
mDetached = false;
mRetaining = false;
mLoaderManager = null;
mLoadersStarted = false;
mCheckedForLoaderManager = false;
}
该部分只是了解Fragment存在哪些域、初始化状态是什么,方便后面分析。
BackStackRecord.class (FragmentTransaction)###
final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable
Fields####
final FragmentManagerImpl mManager;
Op mHead;
Op mTail;
int mNumOp;
static final class Op {
Op next;
Op prev;
int cmd;
Fragment fragment;
......
ArrayList<Fragment> removed;
}
FragmentManager的beginTransaction方法实则是创建了如下的一个FragmentTransaction对象
BackStackRecord()@BackStackRecord.class####
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
FragmentTransaction中存储的每个事务实际是一个Op对象,该对象存储有当前事务的操作类型-cmd、当前事务的操作对象-fragment;下面以add方法为例进行介绍:
add()@BackStackRecord.class####
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
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 (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment " + fragment + ": was " + fragment.mFragmentId + " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
} //不能改变Fragment所属ViewGroup
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
void addOp(Op op) {
if (mHead == null) { mHead = mTail = op; }
else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
.....
mNumOp++;
}
将op添加到链表尾部
commit()@BackStackRecord.class####
该方法是将BackStackRecord.this提交给UI线程去执行,具体执行BackStackRecord.class中实现的run方法
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
mCommitted = true;
if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this);} //默认是false
else { mIndex = -1; }
mManager.enqueueAction(this, allowStateLoss); //note1
return mIndex;
}
1、重点是这里,将会导致异步执行BackStackRecord的run方法
run()@BackStackRecord.class####
public void run() {
...
TransitionState state = null;
SparseArray<Fragment> firstOutFragments = null;
SparseArray<Fragment> lastInFragments = null;
if (SUPPORTS_TRANSITIONS) { //当前版本大于21,Build.VERSION.SDK_INT >= 21则执行下面代码
firstOutFragments = new SparseArray<Fragment>();
lastInFragments = new SparseArray<Fragment>();
calculateFragments(firstOutFragments, lastInFragments);
//Finds the first removed fragment and last added fragments when going forward
state = beginTransition(firstOutFragments, lastInFragments, false);
}
int transitionStyle = state != null ? 0 : mTransitionStyle;
int transition = state != null ? 0 : mTransition;
Op op = mHead; //note1
while (op != null) {
......
switch (op.cmd) {
case OP_ADD: { //note2
Fragment f = op.fragment;
......
mManager.addFragment(f, false);
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i=0; i<mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (old.mContainerId == containerId) {
if (old == f) { op.fragment = f = null; }
else {
if (op.removed == null) { op.removed = new ArrayList<Fragment>(); }
op.removed.add(old); //存入op的链表中
old.mNextAnim = exitAnim;
......
mManager.removeFragment(old, transition, transitionStyle);
} //end of else
} //end of if (old.mContainerId == containerId)
} end of for
} end of if (mManager.mAdded != null)
if (f != null) {//证明当前的Fragment在FragmentManager的mAdded数组中不存在,需要添加到该数组中
......
mManager.addFragment(f, false);
}
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
......
mManager.removeFragment(f, transition, transitionStyle); //后面的两个参数在分析的时候为简单起见,全部看成为0
} break;
case OP_HIDE: {
Fragment f = op.fragment;
......
mManager.hideFragment(f, transition, transitionStyle);
} break;
case OP_SHOW: {
Fragment f = op.fragment;
......
mManager.showFragment(f, transition, transitionStyle);
} break;
case OP_DETACH: {
Fragment f = op.fragment;
......
mManager.detachFragment(f, transition, transitionStyle);
} break;
case OP_ATTACH: {
Fragment f = op.fragment;
......
mManager.attachFragment(f, transition, transitionStyle);
} break;
default: { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); }
}// end of switch
op = op.next;
} //end of while
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
.....
}
1、当前BackStackRecord存储的所有事务的链表头结点
2、这里的op对象是之前的add()方法产生的一个事务,最终调用mManager.addFragment(f, false)方法;
往下我们会看一下FragmentManager的addFragment方法底层实现,不过我们会先看下beginTransaction()和enqueueAction()两个方法;前者获取FragmentTransaction对象,后者将FragmentTransaction对象交给UI线程去执行。
FragmentManagerImpl.class(FragmentManager)###
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory
Fields####
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<BackStackRecord> mBackStack;
boolean mDestroyed;
FragmentHostCallback mHost;
//提供主线程的Handler,FragmentManagerImpl所属的Activity,在FragmentActivity的onCreate方法中会对其进行初始化
ArrayList<Runnable> mPendingActions; //需要执行的异步事务
boolean mNeedMenuInvalidate; //当前Fragment需要菜单栏
int mCurState = Fragment.INITIALIZING;//当前FragmentManager下的所有Fragment应该到达的状态
attachController()@FragmentManager.class####
public void attachController(FragmentHostCallback host, FragmentContainer container, Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
}
该方法会在Fragment的onCreate方法中会被调用,主要是给mHost赋值
beginTransaction()@FragmentManager.class####
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
enqueueAction()@FragmentManager.class
public void enqueueAction(Runnable 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<Runnable>(); }
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
Runnable mExecCommit = new Runnable() {
@Override
public void run() { execPendingActions(); } //该方法内部就会将mPendingActions中的action顺序调用run方法执行
};
addFragment()@FragmentManager.class####
public void addFragment(Fragment fragment, boolean moveToStateNow) { //第二个参数默认是false
if (mAdded == null) { mAdded = new ArrayList<Fragment>();}
makeActive(fragment); //添加到mActive集合中
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {throw new IllegalStateException("Fragment already added: " + fragment); }
mAdded.add(fragment); //添加到mAdded集合中
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {mNeedMenuInvalidate = true; }
if (moveToStateNow) {moveToState(fragment);} //note1
}
}
1、默认情况不会执行这个方法。
在BackStackRecord的run方法最后会调用mManager.moveToState (mManager.mCurState, transition, transitionStyle, true)方法。
在FragmentManager中存在多个moveToState方法,按照参数类型个人将其分两类,一类是参数中有Fragment的moveToState方法,另一类自然就是参数中无Fragment的moveToState方法。第一类是针对一个特定的Fragment进行操作,主要工作就是将指定的Fragment状态转移到FragmentManager的mCurState状态。第二类就是更新FragmentManager的mCurState状态!下面先介绍不带Fragment参数的moveToState方法。
moveToState(参数不带Fragment)@FragmentManager.class#####
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
void moveToState(int newState, int transit, int transitStyle, boolean always) {
......
mCurState = newState; //note1
if (mActive != null) {
boolean loadersRunning = false;
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i); //note2
if (f != null) {
moveToState(f, newState, transit, transitStyle, false);
.......
}
}
......
if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
mHost.onSupportInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
}
1、更新FragmentManager当前的状态,即对mCurState赋值。
2、遍历mActive集合中的Fragment数据并调用带Fragment参数的moveToState方法。
不带Fragment参数的moveToSate方法是将FragmentManager下面的所有Fragment状态转移到当前FragmentManager的状态,Fragment可能向前转移(创建过程)也可能向后转移(销毁过程)。
其实FragmentManager的参数不带Fragment的moveToState()方法是下列方法底层实现:dispatchDestroy()、dispatchDestroyView()、dispatchStop()、dispatch Pause()、dispatchResume()、dispatchStart()、dispatchActivity Created() 和dispatchCreate()方法,而这些方法会被FragmentActivity调用,如FragmentActivity的onCreate方法会调用mFragments.dispatchCreate();FragmentActivity的onStart方法会调用mFragments.dispatchActivityCreated()、mFragments.dispatchStart()两个方法;以此类推基本都能找到在FragmentActivity对应的调用!FragmentActivity调用不带Fragment参数的moveToState方法主要是设置当前的FragmentManager的状态!
备注: class AppCompatActivity extends FragmentActivity,即AppCompat Activity可以使用Fragment,使用方式一样
moveToState(参数带Fragment)@FragmentManager.class#####
下面这个方法很长,真的很很很长,可是我看嗨了(其实一开始我是拒绝的(ノへ ̄、))。。。。因为可以说这一个方法就囊括了整个Fragment所有的生命周期、完成对用户自定义方法的调用、将Fragment产生的视图添加进入ViewGroup中等等,它能能满足你对Fragment大多数的幻想。读完你可以发现Fragment的生命周期是基于它的状态变量!听说在正式阅读下面方法前,看看上面Fragment的使用,效果会更好哟~。
void moveToState(Fragment f) {
moveToState(f, mCurState, 0, 0, false);
}
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
//参数值如:mManager.mCurState,0, 0, true
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) { newState = Fragment.CREATED; }
if (f.mRemoving && newState > f.mState) { newState = f.mState; }
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { newState = Fragment.STOPPED; }
if (f.mState < newState) {
......
switch (f.mState) {
case Fragment.INITIALIZING:
.......
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
f.onAttach(mHost.getContext());//note-1
if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f + " did not call through to super.onAttach()"); }
if (f.mParentFragment == null) { mHost.onAttachFragment(f); }
if (!f.mRetaining) { f.performCreate(f.mSavedFragmentState); } //note0
f.mRetaining = false;
if (f.mFromLayout) { //Fragment来自于布局文件
f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), null, f.mSavedFragmentState); //note1
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); //note2
}
else { f.mInnerView = null; }
} //注意这里没有break!因此往下继续执行
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
container = (ViewGroup)mContainer.onFindViewById(f.mContainerId); //note3
if (container == null && !f.mRestored) { throwException(new IllegalArgumentException( "No view found for id 0x....."); }
}
f.mContainer = container;
f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), container, f.mSavedFragmentState);//note4
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) {
Animation anim = loadAnimation(f, transit, true,transitionStyle);//note5
if (anim != null) {
setHWLayerAnimListenerIfAlpha(f.mView, anim);
f.mView.startAnimation(anim);
}
container.addView(f.mView);//note6
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);//note6.5
}
else { f.mInnerView = null;}
}
f.performActivityCreated(f.mSavedFragmentState);//note7
if (f.mView != null) {f.restoreViewState(f.mSavedFragmentState);}
f.mSavedFragmentState = null;
} //注意这里没有break!因此往下继续执行
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) { f.performStart();} //note8
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
f.mResumed = true;
f.performResume(); //note9
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}//end of swith
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
f.performPause(); //note10
f.mResumed = false;
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) { f.performStop();} //note11
case Fragment.STOPPED:
if (newState < Fragment.STOPPED) {f.performReallyStop();} //note12
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
if (f.mView != null) {
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { saveFragmentViewState(f);}
}
f.performDestroyView(); //note13
if (f.mView != null && f.mContainer != null) {
Animation anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
anim = loadAnimation(f, transit, false,transitionStyle);
}
if (anim != null) {
final Fragment fragment = f;
f.mAnimatingAway = f.mView;
f.mStateAfterAnimating = newState;
final View viewToAnimate = f.mView;
anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(viewToAnimate, anim) {
@Override
public void onAnimationEnd(Animation animation) {
super.onAnimationEnd(animation);
if (fragment.mAnimatingAway != null) {
fragment.mAnimatingAway = null;
moveToState(fragment, fragment.mStateAfterAnimating, 0, 0, false);
}
}
});
f.mView.startAnimation(anim);
}
f.mContainer.removeView(f.mView); //note14
}
f.mContainer = null;
f.mView = null;
f.mInnerView = null;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (mDestroyed) {
if (f.mAnimatingAway != null) {
View v = f.mAnimatingAway;
f.mAnimatingAway = null;
v.clearAnimation();
}
}
if (f.mAnimatingAway != null) {
f.mStateAfterAnimating = newState;
newState = Fragment.CREATED;
}
else {
if (!f.mRetaining) { f.performDestroy();} //note15
f.mCalled = false;
f.onDetach(); //note16
if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f+ " did not call through to super.onDetach()"); }
if (!keepActive) {
if (!f.mRetaining) {makeInactive(f); }
else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
f.mChildFragmentManager = null;
}
}end of if (!keepActive)
}//end of else
}//end of if (newState < Fragment.CREATED)
}//end of switch
}//end of else if (f.mState > newState)
f.mState = newState; //17
}//end of function
-1、onAttach(Context context)
0、onCreate(savedInstanceState)
下面的第1-2步是针对当前Fragment位于一个View Layout里面的情况,即静态而非动态使用Fragment的情况
1、onCreateView(inflater, container, savedInstanceState);
2、onViewCreated(View view, @Nullable Bundle savedInstanceState)
下面的3-6.5是动态使用Fragment的情况
3、获得该Fragment所属的ViewGroup
4、onCreateView(inflater, container, savedInstanceState);
5、载入动画
6、将Fragment获得的View添加到第三步得到的ViewGroup中
6.5、onViewCreated(View view, @Nullable Bundle savedInstanceState)
7、onActivityCreated(savedInstanceState);
8、onStart();
9、onResume();
10、onPause();
11、onStop();
13、onDestroyView();
14、将当前View从ViewGroup中移除出去
15、onDestroy();
16、onDetach()
17、更新参数Fragment的状态和FragmentManager的状态相同
通过对该方法的分析,我们得出FragmentManager通过调用Fragment对象相关方法,使得Fragment状态最终转移到和FragmentManager相同的状态。具体状态分为Initial、Created、ActivityCreated、Stopped、Start、Resume共6个状态。预期状态(newState)大于Fragment自身的状态(f.mState < newState)则将Fragment的状态向前推进即下图的左边方向,对应Fragment的创建过程;预期状态(newState)小于Fragment自身的状态(f.mState > newState)则将Fragment的状态向后推进即下图的右边方向,对应Fragment的销毁过程;
其实FragmentManager中带Fragment参数的moveToState方法是下列方法底层实现:detachFragment、attachFragment、removeFragment、addFragment等方法,这些方法不会在FragmentActivity中出现,但是会在FragmentTransaction中的run方法中出现,即每次提交的事务最终会调用这些方法完成实际的Fragment的加载与销毁。