Fragment 源码解读和使用。
中间部分: FrameLayout(ViewGroup) +Fragment, 选择某个tab再加载其里面的数据。需要左右滑动,也可以给Fragment切换添加动画。
而非ViewPager+Fragment。 要设置Adapter,除非设置setOffscreenPageLimit(4) 预加载4个页面。适合左右滑动场景。
TabHostFragment
简介--- Fragment片段。
Android 3.0以上引入了。
自己的生命周期:onAttach()/ onCreateView() 传递资源xml设置UI /onDestroyView() ...
通过代码方式添加到某个ViewGroup中。
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
FindFragment fragment = new FindFragment();
// 参数1:要放置片段的位置,有资源id指定。 替换replace()
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
add方法分析。
add(containerId, fragment); 只是设置了一些参数。调用commit方法,才会执行其逻辑。
-- doAddOp(containerViewId, fragment, null, OP_ADD);
// FragmentTransaction.java
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
final Class<?> fragmentClass = fragment.getClass(); // 反射
final int modifiers = fragmentClass.getModifiers();
if(tag!=null) {
fragment.mTag = tag;
}
if (containerViewId != 0) {
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment)); // 添加到集合中。
}
// ArrayList<Op> mOps = new ArrayList<>();
void addOp(Op op) {
mOps.add(op);
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
commit() 提交方法
-- commitInternal(false)
-- mManager.enqueueAction(this, allowStateLoss)
-- mHost.getHandler().post(mExecCommit); // 使用异步
-- execPendingActions()
-- startPendingDeferredFragments() //
-- performPendingDeferredStart(fragment)
-- moveToState(f, mCurState, 0, 0, false) // 移动到当前状态。
case Fragment.INITIALIZING:
-- f.onAttach(mHost.getContext())-->onAttach() // 调用Fragment的attach生命周期函数。
-- mHost.onAttachFragment(f)
-- f.performCreate(f.mSavedFragmentState) // 执行onCreate生命周期。
-- f.mView = f.performCreateView()--> 回调onCreateView()方法,返回布局。
-- f.onViewCreated(f.mView, f.mSavedFragmentState)
case Fragment.CREATED:
-- container = (ViewGroup)mContainer.onFindViewById(f.mContainerId)
-- f.mView = f.performCreateView() // 拿到首页的界面。???调用两次?
-- container.addView(f.mView)
-- f.onViewCreated(f.mView, f.mSavedFragmentState)
-- f.performActivityCreated(f.mSavedFragmentState)
replace 替换方法分析。 support-V4:23.4.0
总结:把之前的Fragment移除,重新执行Fragment的生命周期(会重新绘制UI界面)。
所以之前的状态就不存在了。
-- replace(viewId, fragment)
-- replace(viewId, fragment, null)
-- doAddOp(containerViewId, fragment, tag, OP_REPLACE);
BackStackRecord.java
-- case OP_REPLACE:
-- Fragment old = mManager.mAdded.get(i) // 遍历拿到老的,最后一个Fragment。
-- op.removed.add(old);
mManager.removeFragment(old, transition, transitionStyle) // 会把上一个Fragment被移除。执行其onDestroy
mManager.addFragment(f, false) // 把新的Fragment加进来。
case OP_REPLACE: {
final Fragment f = op.fragment;
final int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
final Fragment old = added.get(i); // 拿到最后一个
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
// This is duplicated from above since we only make
// a single pass for expanding ops. Unset any outgoing primary nav.
if (old == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
opNum++;
oldPrimaryNav = null;
}
final Op removeOp = new Op(OP_REMOVE, 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;
6. 解决思路
如果容器中没有就去add添加;否则,就去显示(显示之前需要把所有已经添加的Fragment不显示(隐藏hide))
replace?
先隐藏当前所有 Fragment,fragmentManager.getFragments() 拿到容器所有的。
7.代码封装
package com.tom.joke.fragment;
import java.util.List;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
/**
* 封装代码
*/
public class FragmentManagerHelper {
private FragmentManager mFragmentManager; // 管理类
private int mContainerViewId; // 容器布局 viewId
public FragmentManagerHelper(@Nullable FragmentManager fragmentManager,
@IdRes int containerViewId) {
this.mFragmentManager = fragmentManager;
this.mContainerViewId = containerViewId;
}
// 初始化加载Fragment
public void add(Fragment fragment) {
FragmentTransaction fTransaction = mFragmentManager.beginTransaction();
fTransaction.add(mContainerViewId, fragment);
fTransaction.commit();
}
// 切换显示Fragment。
public void switchFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
// 先隐藏已添加的所有Fragment
List<Fragment> fragments = mFragmentManager.getFragments();
for(Fragment f: fragments) {
fragmentTransaction.hide(f);
}
// 2.容器中没有,就添加add;否则显示show。
if (!fragments.contains(fragment)) {
fragmentTransaction.add(mContainerViewId, fragment);
}else {
fragmentTransaction.show(fragment);
}
// fragmentTransaction.replace(R.id.main_tab_fl, mHomeFragment); // 替换Fragment
fragmentTransaction.commit();
}
}