翻车了,字节一道 Fragment面试题(1)

D/MainFragment: onCreateAnimator:

D/MainFragment: onStart:

D/MainActivity: onStart:

D/MainActivity: onResume:

D/MainFragment: onResume:

可以看到Activity 在oncreate开始时,Fragment紧接着attach,create,然后activity执行完毕onCreate方法

此后都是Fragment在执行,直到onStart方法结束

然后轮到Activity,执行onStart onResume

也就是,Activity 创建的时候,Fragment一同创建,同时Fragment优先在后台先展示好,最后Activity带着Fragment一起展示到前台。

是什么?

====

Fragment中文翻译为”碎片“,在手机中,每一个Activity作为一个页面,有时候太大了,尤其是在平板的横屏下,我们希望左半边是一根独立模块,右半边是一个独立模块,比如一个新闻app,左边是标题栏,右边是显示内容

此时就非常适合Fragment

Fragment是内嵌入Activity中的,可以在onCreateView中加载自定义的布局,使用LayoutInflater,然后Activity持有FragmentManager对Fragment进行控制,下图是他的代码框架

img

我们的Activity一般是用AppCompatActivity,而AppCompatActivity继承了FragmentActivity

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,

TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {

也就是说Activity之所支持fragment,是因为有FragmentActivity,他内部有一个FragmentController,这个controller持有一个FragmentManager,真正做事的就是这个FragmentManager的实现类FragmentManagerImpl

整体架构

====

回到我们刚才的面试题,关于生命周期绝对是重中之重,但是实际上,生命周期本质只是被其他地方的方法被动调用而已,关键是Fragment自己的状态变化了,才会回调生命周期方法,所以我们来看看fragment的状态转移

static final int INITIALIZING = 0; 初始状态,Fragment 未创建

static final int CREATED = 1; 已创建状态,Fragment 视图未创建

static final int ACTIVITY_CREATED = 2; 已视图创建状态,Fragment 不可见

static final int STARTED = 3; 可见状态,Fragment 不处于前台

static final int RESUMED = 4; 前台状态,可接受用户交互

fragment有五个状态,

调用过程如下

img

Fragment的状态转移过程主要受到宿主,事务的影响,宿主一般就是Activity,在我们刚刚的题目中,看到了Activity与Fragment的生命周期交替执行,本质上就是,Activity执行完后通知了Fragment进行状态转移,而Fragment执行了状态转移后对应的回调了生命周期方法

下图可以更加清晰

img

宿主改变Fragment状态


那么我们不禁要问,Activity如何改变Fragment的状态?

我们知道Activity继承于FragmentActivity,最终是通过持有的FragmentManager来控制Fragment,我们去看看

FragmentActivity

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

mFragments.attachHost(null /parent/);

super.onCreate(savedInstanceState);

mFragments.dispatchCreate();

}

可以看到,onCreate方法中执行了mFragments.dispatchCreate();,看起来像是通知Fragment的onCreate执行,这也印证了我们开始时的周期回调顺序

D/MainActivity: MainActivity:

D/MainActivity: onCreate: start // 进入onCreate

D/MainFragment: onAttach: // 执行mFragments.dispatchCreate();

D/MainFragment: onCreate:

D/MainActivity: onCreate: end // 退出onCreate

类似的FragmentActivity在每一个生命周期方法中都做了相同的事情

@Override

protected void onDestroy() {

super.onDestroy();

if (mViewModelStore != null && !isChangingConfigurations()) {

mViewModelStore.clear();

}

mFragments.dispatchDestroy();

}

我们进入dispatchCreate看看,

Runnable mExecCommit = new Runnable() {

@Override

public void run() {

execPendingActions();

}

//内部修改了两个状态

public void dispatchCreate() {

mStateSaved = false;

mStopped = false;

dispatchStateChange(Fragment.CREATED);

private void dispatchStateChange(int nextState) {

try {

mExecutingActions = true;

moveToState(nextState, false);// 转移到nextState

} finally {

mExecutingActions = false;

}

execPendingActions();

}

//一路下来会执行到

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.mAdded || f.mDetached) && newState > Fragment.CREATED) {

newState = Fragment.CREATED;

}

if (f.mRemoving && newState > f.mState) {

if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {

// Allow the fragment to be created so that it can be saved later.

newState = Fragment.CREATED;

} else {

// While removing a fragment, we can’t change it to a higher state.

newState = f.mState;

}

}

}

可以看到上面的代码,最终执行到 moveToState,通过判断Fragment当前的状态,同时newState > f.mState,避免状态回退,然后进行状态转移

状态转移完成后就会触发对应的生命周期回调方法

事务管理


如果Fragment只能随着Activity的生命周期变化而变化,那就太不灵活了,所以Android给我们提供了一个独立的操作方案,事务

同样由FragManager管理,具体由FragmentTransaction执行,主要是添加删除替换Fragment等,执行操作后,需要提交来保证生效

FragmentManager fragmentManager = …

FragmentTransaction transaction = fragmentManager.beginTransaction();

transaction.setReorderingAllowed(true);

transaction.replace(R.id.fragment_container, ExampleFragment.class, null); // 替换Fragment

transaction.commit();// 这里的commit是提交的一种方法

Android给我们的几种提交方式

image-20211020143006614

FragmentTransaction是个挂名抽象类,真正的实现在BackStackState回退栈中,我们看下commit

@Override

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);//1

} else {

mIndex = -1;

}

// 入队操作

mManager.enqueueAction(this, allowStateLoss);//2

return mIndex;

}

可以看到,commit的本质就是将事务提交到队列中,这里出现了两个数组,注释1处

ArrayList mBackStackIndices;

ArrayList mAvailBackStackIndices;

public int allocBackStackIndex(BackStackRecord bse) {

synchronized (this) {

if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {

if (mBackStackIndices == null) {

mBackStackIndices = new ArrayList();

}

int index = mBackStackIndices.size();

mBackStackIndices.add(bse);

return ind

} else {

int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);

mBackStackIndices.set(index, bse);

return index;

}

}

}

mBackStackIndices数组,每个元素是一个回退栈,用来记录索引。比如说,当有五个BackStackState时,移除掉1,3两个,就是在mBackStackIndices将对应元素置为null,然后mAvailBackStackIndices会添加这两个回退栈,记录被移除的回退栈

当下次commit时,就判定mAvailBackStackIndices中的索引,对应的BackStackState一定是null,直接写到这个索引即可

而一组操作都commit到同一个队列里面,所以要么全部完成,要么全部不做,可以保证原子性

注释二处是一个入队操作

public void enqueueAction(OpGenerator action, boolean allowStateLoss

synchronized (this) {

mPendingActions.add(action);

scheduleCommit(); // 真正的提交

}

}

public 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); // 发送请求

}

}

尾声

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

  • 思维脑图
  • 性能优化学习笔记


  • 性能优化视频

    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
    顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

  • 思维脑图
    [外链图片转存中…(img-bvBlpKyY-1715358167259)]

  • 性能优化学习笔记
    [外链图片转存中…(img-8AfSMPQC-1715358167260)]
    [外链图片转存中…(img-HgQudEVk-1715358167260)]

[外链图片转存中…(img-SQ0djc2L-1715358167261)]
[外链图片转存中…(img-PNUNzESa-1715358167261)]

  • 性能优化视频
    [外链图片转存中…(img-TcUCUQfX-1715358167261)]
    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>