前言
最近公司动荡,我在的项目受大环境影响收益每年下滑,可能要领盒饭了,所以最近都在复习相关基础内容,毕竟小脑袋瓜会忘记以前学过的东西。
在ViewPager和Fragment的懒加载中,具体的原理是怎么样的呢?为什么能只执行显示的Fragment的onResume方法?
疑问
借用一篇文章的说明
1.Lifecycle.State.STARTED对应Fragment的STARTED状态,如果当前Fragment状态低于STARTED,那么Fragment的状态会变为STARTED,以当前Fragment状态为CREATED为例,接下来会依次执行onCreateView()、onActivityCreate()和onStart()方法;
2.如果当前Fragment状态高于STARTED,也就是RESUMED,那么Fragment的状态会被强制降为STARTED,接下来会执行onPause()方法。
疑问一:设置STARTED后是否执行onResume?那是否能交互?
疑问二:FragmentPagerAdapter如果设置STARTED的话,就不会执行到onResume方法,懒加载就无法实现,更没有降级一说?
探索
疑问一:
实践是检验最好的结果,
设置CREATE的:只走了onCreate方法,onStart和onResume不触发,fragment也不显示
设置STARTED的话:不执行onResume,但也不影响页面可交互。
前备知识在疑问二有记录
疑问二
原有的懒加载是用 setUserVisibleHint实现,但查看源码已经给设置成@Deprecated
注释的setMaxLifecycle是什么呢?单看意思就是最大生命周期,就是一个生命周期阻断的作用。
用法如下
FragmentTransaction mCurTransaction = getSupportFragmentManager().beginTransaction();
mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);
其中的入参中LifeCycle.State是个枚举类型,
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
START,
/**
* Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached after {@link android.app.Activity#onResume() onResume} is called.
*/
RESUMED;
}
看注释大概意思是:
START:创建生命周期只会执行到onStart(onResume不执行),之后的都统一是onPause(onStop不执行)。
fragment创建:onAttach->onCreate->onCreateView->onActivityCreate->onStart->onResume
fragment结束:onPause->onStop->onDestoryView->onDestory->onDetach
知道这些我们再看看FragmentPagerAdapter的源码
首先时构造函数
mBehavior设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT才会懒加载
而用到BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT判断只有两个地方:
1.创建Fragment
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
***省略
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {//注意不执行setUserVisibleHint
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
} else {
fragment.setUserVisibleHint(false);
}
}
return fragment;
}
其实就是BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT的时候设置setMaxLifecycle为Lifecycle.State.STARTED,也就是说ViewPager的所有fragment的生命周期只会走到onStart,那onResumet是何时调用?
2.设置当前fragment
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;//即将显示的fragment
if (fragment != mCurrentPrimaryItem) {//mCurrentPrimaryItem为即将隐藏的fragment
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {//开启懒加载
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);//设置即将隐藏的fragment为Start状态
} else {
mCurrentPrimaryItem.setUserVisibleHint(false);
}
}
fragment.setMenuVisibility(true);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {//懒加载
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
//主要标注1
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);//设置即将显示的fragemnt为Resume状态
} else {
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;//mCurrentPrimaryItem 只有这里赋值 默认为空
}
}
代码中会将即将显示的fragment 调用setMaxLifecycle方法设置为 RESUMED,所以即将显示的fragment会调用onResume方法
而上一个显示的Fragmentm(CurrentPrimaryItem设)会置Lifecycle为START,由于之前设置是RESUMED且执行了onResume,超过了START的限制会回退生命周期,并执行onPause方法,然后隐藏当前实例。
生命周期:
首次进入
log: fragment1:onCreate
log: fragment2:onCreate
log: fragment1:onActivityCreated
log: fragment1:onStart
log: fragment2:onActivityCreated
log: fragment2:onStart
log: fragment1:onResume
切换到fragmet2
log: fragment1:onPause
log: fragment2:onResume
home健
log: fragment2:onPause
再次打开app
log: fragment1:onStart
log: fragment2:onStart
log: fragment2:onResume
退出页面
log: fragment1:onPause
log: fragment2:onDestroy
log: fragment2:onDestroy
instantiateItem和setPrimaryItem的调用链是:
ViewPager.setAdapter->setCurrentItemInternal->populate->addNewItem/ mAdapter.setPrimaryItem
总结
疑问一:设置STARTED后是否执行onResume?那是否能交互?
疑问二:FragmentPagerAdapter如果设置STARTED的话,就不会执行到onResume方法,懒加载就无法实现,更没有降级一说?
1、设置STARTED后是不会执行onResume,包括当前要显示的fragment,也不会影响用户交互。
2、FragmentPagerAdapter会先设置MaxLifecycle的状态为STARTED,然后执行setPrimaryItem方法时会将要显示的Fragment设置为RESUMED,故显示的Fragment会执行onResume。最后设置上一个Fragment的状态为STARTSED,并调用其的onPause方法
STARTSED状态说明:after onStart call;right before onPause call