最近公司的项目做性能优化,正在折腾Fragment懒加载的东西,由于项目迁移到了AndroidX,懒加载方案和以前有所不同,不过总体来说代码量少了很多,正好可以对新老版本的懒加载方案做一个对比,下面是关于AndroidX前和AndroidX后的fragment懒加载方案总结
AndroidX之前采用旧懒加载方案
4步优化
- View已加载且fragment可见时懒加载
- 当onViewCreated()方法执行时,表明View已经加载完毕,isViewCreated标记为true,并调lazyLoad()方法
- 当setUserVisibleHint(boolean isVisibleToUser)执行时,isVisibleToUser为true并调lazyLoad()方法
- 在lazyLoad()方法双重标记判断,再进行停止一切/加载数据事件分发
- 定义抽象方法loadData(),子类重写进行加载数据
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
45private boolean isViewCreated = false;
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
...
isViewCreated = true; // View已加载
// 此时正好可见
if (getUserVisibleHint()) {
setUserVisibleHint(true);
}
return rootView;
}
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
// View已加载
if (isViewCreated) {
// 根据当前可见状态分发事件
if (isVisibleToUser) {
dispatchUserVisibleHint(true);
} else {
dispatchUserVisibleHint(false);
}
}
}
private void dispatchUserVisibleHint(boolean visibleState) {
if (visibleState) {
// 加载网络数据请求
onFragmentLoad();
} else {
// 停止网络数据请求
onFragmentLoadStop();
}
}
public void onFragmentLoadStop() {
E("onFragmentLoadStop");
}
public void onFragmentLoad() {
E("onFragmentLoad");
}
- 记录上一次状态与当前状态比较,保证变化过程,状态未改变不需要分发事件
- 从可见到不可见,停止一切操作
- 从不可见到可见,加载数据操作
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
28private boolean isVisibleStateUP = false; // 记录上一次可见的状态
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isViewCreated) {
// 当前可见且上一次不可见
if (isVisibleToUser && !isVisibleStateUP) {
dispatchUserVisibleHint(true);
}
// 当前不可见且上一次可见
else if (!isVisibleToUser && isVisibleStateUP){
dispatchUserVisibleHint(false);
}
}
}
private void dispatchUserVisibleHint(boolean visibleState) {
this.isVisibleStateUP = visibleState;
if (visibleState) {
// 加载网络数据请求
onFragmentLoad();
} else {
// 停止网络数据请求
onFragmentLoadStop();
}
}
- 启动新的Activity没有分发事件
- 除了onCreate和setUserVisibleHint在onResume/onPause中也要分发事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void onResume() {
super.onResume();
// 当前可见且上一次不可见
if (getUserVisibleHint() && !isVisibleStateUP) {
dispatchUserVisibleHint(true);
}
}
public void onPause() {
super.onPause();
// 当前不可见且上一次可见
if (getUserVisibleHint() && isVisibleStateUP) {
dispatchUserVisibleHint(false);
}
}
- 双重嵌套下子Fragment无法接收到事件
父fragment不可见直接返回,判断当前fragment是否可见,手动遍历分发每个子fragment停止一切操作/加载数据事件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// 判断父fragment是否可见
private boolean isParentInvisible() {
// 获取父fragment
Fragment parentFragment = getParentFragment();
// 父fragment是懒加载fragment的实例
if (parentFragment instanceof LazyFragment) {
LazyFragment fragment = (LazyFragment) parentFragment;
// 父fragment不可见
return !fragment.isVisibleStateUP;
}
return false;
}
private void dispatchUserVisibleHint(boolean visibleState) {
this.isVisibleStateUP = visibleState;
// 当前fragment可见且父fragment不可见,不分发事件
if (visibleState && isParentInvisible()) {
return;
}
if (visibleState) {
onFragmentLoad();
// 分发子fragment可见事件
dispatchChildVisibleState(true);
} else {
onFragmentLoadStop();
// 分发子fragment不可见事件
dispatchChildVisibleState(false);
}
}
protected void dispatchChildVisibleState(boolean state) {
FragmentManager fragmentManager = getChildFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
if (fragments != null) {
// 遍历子Fragment分发事件
for (Fragment fragment: fragments) {
// fragment是懒加载实例未被隐藏且可见
if (fragment instanceof LazyFragment &&
!fragment.isHidden() &&
fragment.getUserVisibleHint()) {
((LazyFragment5)fragment).dispatchUserVisibleHint(state);
}
}
}
}AndroidX之后采用新懒加载方案
Google在Androidx在FragmentTransaction中增加了setMaxLifecycle方法控制Fragment 调用的最大的生命周期函数。该方法可以设置活跃状态下Fragment最大状态,如果该Fragment 超过了设置的最大状态,会强制将Fragment降级到正确的状态viewPager下设置adapter的behavior
BEHAVIOR_SET_USER_VISIBLE_HINT:Fragment对用户可见状态发生改变时,setUserVisibleHint方法会被调用。
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT:当前选中的Fragment在Lifecycle.State#RESUMED状态,其他不可见的 Fragment限制在Lifecycle.State#STARTED状态1
2
3
4
5
6
7
8
9
10
11
12
13open class FragmentLazyPagerAdapter(
fragmentManager: FragmentManager,
private val fragments: MutableList<Fragment>,
private val titles: MutableList<String>
) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int) = fragments[position]
override fun getCount() = fragments.size
override fun getPageTitle(position: Int) = titles[position]
}封装懒加载fragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21abstract class LazyFragment : Fragment() {
// 是否加载过标记
private var isLoaded = false
override fun onResume() {
super.onResume()
if (!isLoaded) {
lazyInit()
Log.d(TAG, "lazyInit:!!!!!!!")
isLoaded = true
}
}
override fun onDestroyView() {
super.onDestroyView()
isLoaded = false
}
abstract fun lazyInit()
}add/show/hide时设置最大生命周期(未使用viewPager)
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// 初始化fragment
private fun loadFragmentsTransaction(
@IdRes containerViewId: Int,
showPosition: Int,
fragmentManager: FragmentManager,
vararg fragments: Fragment
) {
if (fragments.isNotEmpty()) {
fragmentManager.beginTransaction().apply {
for (index in fragments.indices) {
val fragment = fragments[index]
add(containerViewId, fragment, fragment.javaClass.name)
if (showPosition == index) {
setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
} else {
hide(fragment)
setMaxLifecycle(fragment, Lifecycle.State.STARTED)
}
}
}.commit()
} else {
throw IllegalStateException(
"fragments must not empty"
)
}
}
// 展示/隐藏fragment
private fun showHideFragmentTransaction(fragmentManager: FragmentManager, showFragment: Fragment) {
fragmentManager.beginTransaction().apply {
show(showFragment)
setMaxLifecycle(showFragment, Lifecycle.State.RESUMED)
//获取其中所有的fragment,其他的fragment进行隐藏
val fragments = fragmentManager.fragments
for (fragment in fragments) {
if (fragment != showFragment) {
hide(fragment)
setMaxLifecycle(fragment, Lifecycle.State.STARTED)
}
}
}.commit()
}Fragment嵌套下的问题
第一次初始化时,同级不可见的Fragment仍然要调生命周期方法,需增加Fragment是否可见的判断1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22abstract class LazyFragment : Fragment() {
private var isLoaded = false
override fun onResume() {
super.onResume()
//增加Fragment是否可见的判断
if (!isLoaded && !isHidden) {
lazyInit()
Log.d(TAG, "lazyInit:!!!!!!!")
isLoaded = true
}
}
override fun onDestroyView() {
super.onDestroyView()
isLoaded = false
}
abstract fun lazyInit()
}ViewPager2懒加载
最新的ViewPager2默认就实现了懒加载,可以说不用任何处理
但是ViewPager2中的RecyclerView可以缓存Fragment的数量是有限的,会造成Fragment的多次销毁和创建,也可通过setOffscreenPageLimit()方法设置预加载数量,再用AndroidX下的懒加载fragment方式去处理