说到管理Activity中的Fragment,自然就要重点说一下FragmentManager,之前已经说过了,getFragmentManager()获取到的FragmentManager支持原生的Fragment,而getSupportFragmentManager()支持的是v4包的Fragment。
获取Fragment的方法
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_study1"
android:name="com.example.study.StudyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<fragment
android:id="@+id/fragment_study2"
android:name="com.example.study.StudyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<fragment
android:tag="fragment_second"
android:name="com.example.study.SecondFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
获取Fragment的三种方式
fragmentManager = getSupportFragmentManager()
// 通过id查找对应的Fragment实例
fragment1 = (StudyFragment) fragmentManager.findFragmentById(R.id.fragment_study1)
// 通过tag找到对应的Fragment,在动态加载和静态加载中都可以使用
secondFragment = (SecondFragment) fragmentManager.findFragmentByTag("fragment_second")
// 获取添加到FragmentManager的所有Fragment,通过index访问,0代表最早添加的Fragment
fragmentManager.getFragments()
FragmentManager是如何管理Fragment的
每次我们对Fragment的操作都需要通过FragmentTransaction,到了这里估计很多博客都已经说到了FragmentTransaction里面的几个操作方法,虽然在下也是要说的,顺便说一下Fragment管理的设计吧,不看不知道,看了才知道可牛逼哄哄了。
我们知道,没有FragmenActivity就没有Fragment。
那么为什么我们必须要继承自FragmentActivity呢,这就是Fragment设计上的便利了,开发者希望我们在使用Fragment的时候只需要关注对Fragment的操作,而Fragment的管理则交由FragmentActivity的FragmentManager来实现。
在FragmentAactivity这个类下面,当我们调用getSupportManager的时候
public class FragmentActivity extends BaseFragmentActivityJB implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompatApi23.RequestPermissionsRequestCodeValidator {
···
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
···
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
···
}
我们可以看到FragmentActivity里面有一个FragmentController,这个FragmentController定义了所有对Fragment的管理操作,包括我们的Activity在onCreate,onResume,onDestroy等各种生命周期或回调对Fragment的影响,都是由这个类来控制的。
public class FragmentController {
private final FragmentHostCallback<?> mHost;
/**
* Returns a {@link FragmentController}.
*/
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
/**
* Returns a {@link FragmentManager} for this controller.
*/
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
FragmentHostCallback是一个抽象类,负责调用各种各样的回调,这样的话,当Avtivity的状态,生命周期发生改变的时候,就可以通过这个回调接口进行统一管理,在上面提到的HostCallbacks是FragmentActivity里面的一个继承FragmentHostCallback的内部类。下面我们来看看FragmentHostCallback的默认实现
public abstract class FragmentHostCallback<E> extends FragmentContainer {
private final Activity mActivity;
···
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
···
}
FragmentManagerImpl里面的具体实现就是有关Fragment是如何运行的,各种各样的生命周期,判断Fragment的不同状态,切换状态,Transaction只是用作记录对Fragment的操作记录,最终调用commit的时候,实际上调用的还是FragmentManagerImpl的方法
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
···
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
···
}
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
@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);
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
FragmentManagerImpl的部分实现
/**
* 添加一个操作到待操作队列中
*
* @param action 添加的操作
* @param allowStateLoss 是否允许丢失状态信息
* @throws 如果Activity已经销毁了抛出IllegalStateException异常
*/
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);
}
}
}
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
上面的就是我们通过getSupportFragmentManager()获取到FragmentManager,然后再开启事务,提交事务所经历的代码流程。控制Fragment的生命周期的回调,通过FragmentManager的moveToState方法。
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)
关于Fragment的生命周期,要改篇再学习。现在继续来学习一下FragmentTransaction的一些常用方法
#将一个fragment实例添加到Activity里面指定id的容器中
add(Fragment fragment, String tag)
add(int containerViewId, Fragment fragment)
add(int containerViewId, Fragment fragment, String tag);
#将一个fragment实例从FragmentManager的FragmentList中移除
remove(Fragment fragment);
#只控制Fragment的隐藏
hide(Fragment fragment)
#只控制Fragment的显示
show(Fragment fragment)
#清除视图,从containerid指定的Added列表移除,FragmentList依然保留
detach(Fragment fragment)
#创建视图,添加到containerid指定的Added列表,FragmentList依然保留
attach(Fragment fragment)
#替换containerViewId中的fragment,它会把containerViewId中所有fragment删除,然后添加当前的fragment
replace(int containerViewId, Fragment fragment)
replace(int containerViewId, Fragment fragment, String tag)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
FragmentTransaction的用例
之前的例子都已经对FragmentTransaction的用法有过一些介绍了
private void addFragment(Fragment fragment, String tag){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.fragment_container,fragment,tag);
transaction.commit();
}
private void replaceFragment(Fragment fragment, String tag){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.fragment_container,fragment,tag);
transaction.commit();
}
private void removeFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.remove(fragment);
transaction.commit();
}
private void showFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.show(fragment);
transaction.commit();
}
private void hideFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.hide(fragment);
transaction.commit();
}
private void attachFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.attach(fragment);
transaction.commit();
}
private void detachFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.detach(fragment);
transaction.commit();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
虽然新的Android版本中,Fragment在replace的时候不再重新实例化了(据说在旧的版本会出现这个问题,目前我使用的API 25 ),但是我们还是建议采用show/hide的方式来控制Fragment的显示和隐藏。还有一点需要注意的是,attach和detach会改变Fragment在Added列表中的顺序,从而也会改变Fragment显示的顺序。
FragmentTransaction的事务回退栈
上面介绍了常用的用法,接下来要介绍的是FragmentTransaction的事务回滚,FragmentTransaction把事务添加到回退栈中,只需要在调用 transaction.commit()之前,调用以下代码
transaction.addToBackStack(String tag);
加入回退栈的时候,调用commit方法会返回一个index,作为事务的id,否则返回-1。使用popBackStack方法进行回退,弹出回退栈。
popBackStack()
popBackStack(int id, int flags);
popBackStack(String name, int flags);
flag的取值,当取值0时,表示除了指定这一层之上的所有层都退出栈,指定的这一层为栈顶层;当取值POP_BACK_STACK_INCLUSIVE时,表示连着指定的这一层一起退出栈;
需要注意的是,使用popBackStack()来弹出栈内容的话,调用该方法后会将事物操作插入到FragmentManager的操作队列,只有当轮询到该事物时才能执行。如果想立即执行事物的话,需要使用下面几个对应的方法:
popBackStackImmediate()
popBackStackImmediate(String tag)
popBackStackImmediate(String tag, int flag)
popBackStackImmediate(int id, int flag)
在FragmentActivity的onBackPressed()方法内可以看到,当popBackStackImmediate返回true的情况,则不会执行Activity的onBackPressed()方法
@Override
public void onBackPressed() {
if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
super.onBackPressed();
}
}
2、回退栈(back stack)状态改变监听
FragmentManager还为我们提供了监控回退栈状态改变的方法:
addOnBackStackChangedListener(listener);
removeOnBackStackChangedListener(listener);
通过添加监听器,就可以在回退栈内容改变时,及时收到通知;
(1)、OnCreate()中:
为fragmentManger添加一个监听器:
FragmentManager manager = getSupportFragmentManager();
listener = new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
Log.d("qijian","backstack changed");
}
};
manager.addOnBackStackChangedListener(listener);
(2)、当onDestory()中将监听器remove掉:
protected void onDestroy() {
super.onDestroy();
FragmentManager manager = getSupportFragmentManager();
manager.removeOnBackStackChangedListener(listener);
}
大家一定要注意,不管是这里的回退栈的监听还是其它的监听器,在页面对应的销毁时,都要记得remove掉,不然会造成页面不释放,这也是造成OOM的问题之一。