1.我们最常用的有:①ViewPager + Fragment;②ViewGroup + Fragment ;③TabHost+Fragment
2.今天主要讲ViewGroup+Fragment
- 2.1Fragment的添加
// 加载第一个Fragment 兼容11以下的版本
FragmentManager fragmentManager = getSupportFragmentManager();
// 把第一个Fragment HomeFragment加载进来
mVideoFragment = new VideoFragment();
// 开启事物
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 第一个参数是Fragment的容器id,需要添加的Fragment
transaction.add(R.id.fl_main_content, mVideoFragment);
// 一定要commit
transaction.commit();
- 2.2fragment的替换
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (mAudioFragment == null) {
mAudioFragment = new AudioFragment();
}
//替换
transaction.replace(R.id.fl_main_content, mAudioFragment);
//一定要提交
transaction.commit();
分析现象:每次切换都会重新刷新页面,提交数据
3.Fragment源码分析
3.1Fragment.add方法源码分析
3.1.1getSupportFragmentManager源码分析
//首先看我们写的代码
FragmentManager fragmentManager = getSupportFragmentManager();
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
//最终返回的是FragmentManagerImpl
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
3.1.2看FragmentManagerImpl 中的beginTransaction
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
//最终是将FragmentManagerImpl进行赋值
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
3.1.3BackStackRecord中的add方法
// transaction.add(R.id.fl_main_content, mVideoFragment);
@Override
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) {
//mVideoFragment获得类的对象
final Class fragmentClass = fragment.getClass();
//返回该类的修饰符,如public
final int modifiers = fragmentClass.getModifiers();
//isAnonymousClass该类是不是内部类 isMemberClass是不是成员类
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.");
}
//由上面可以知道是我们自己开启事务后传来的值
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;
}
//R.id.fl_main_content
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);
}
//最终将自己的id传给fragment的参数中
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
//设置参数
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
由上面我们可以知道add只是添加了相关参数
3.3.4commit源码分析:还是在BackStackRecord中
@Override
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
pw.close();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} 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) {
//异步的方法,看mExecCommit
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
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;
}
void doPendingDeferredStart() {
if (mHavePendingDeferredStart) {
boolean loadersRunning = false;
for (int i = 0; i < mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null && f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
if (!loadersRunning) {
mHavePendingDeferredStart = false;
startPendingDeferredFragments();
}
}
}
void startPendingDeferredFragments() {
if (mActive == null) return;
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null) {
performPendingDeferredStart(f);
}
}
}
public void performPendingDeferredStart(Fragment f) {
if (f.mDeferStart) {
if (mExecutingActions) {
// Wait until we're done executing our pending transactions
mHavePendingDeferredStart = true;
return;
}
f.mDeferStart = false;
//移动到当前状态
moveToState(f, mCurState, 0, 0, false);
}
}
3.1.5最终会走到moveToState这个方法,方法太长就直接找有用的
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//没有添加修改当前状态为创建状态
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
...
switch (f.mState) {
case Fragment.INITIALIZING:
....
//fragment的onAttach方法
f.onAttach(mHost.getContext());
...
if (!f.mRetaining) {
//调用framgment的create方法
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
}
if (f.mFromLayout) {
//最终调用的是我们自己复写的onCreateView方法
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
}
....
}
case Fragment.CREATED:{
if (newState > Fragment.CREATED) {
//findviewByid返回一个ViewGroup.也就是我们自己写的FrameLayout
mContainer.onFindViewById(f.mContainerId);
}
//又会调用我们复写的onCreateView 难道自己定义fragment中的onCreateView
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
//添加进去
if (container != null) {
container.addView(f.mView);
}
}
}
}
3.1.6performCreateView源码分析
View performCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
return onCreateView(inflater, container, savedInstanceState);
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return null;
}
3.2fragment的replace方法源码分析:BackStackRecord
@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");
}
//与上面的add的调用方法一模一样,只是参数变了OP_REPLACE
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
3.2.1直接搜索OP_REPLACE
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
//遍历获得已经有的fragment
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);
//移除已经有的fragment
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
op.cmd = OP_ADD;
//又走向了add得到方法
added.add(f);
}
}
replace()的源码就是把之前的移除,会重新执行Fragment生命周期, 会重新绘制界面
解决思路
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (mVideoFragment == null) {
mVideoFragment = new VideoFragment();
}
//首先隐藏所有的fragment
List<Fragment> fragments = fragmentManager.getFragments();
for (Fragment fragment : fragments) {
transaction.hide(fragment);
}
//如果没有则add否则显示
if(!fragments.contains(mVideoFragment)){
transaction.add(R.id.fl_main_content,mVideoFragment);
}else{
transaction.show(mVideoFragment);
}
//替换
//transaction.replace(R.id.fl_main_content, mVideoFragment);
transaction.commit();
我写过一篇文章对fragment的封装,大家可以去看下
http://blog.csdn.net/qq_24675479/article/details/79327825