转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/113545036
本文出自【赵彦军的博客】
前言
还有一个月就过年了,超级开心。
本文所有内容已经上传至github:https://github.com/zyj1609wz/ViewPagerLazyLoad
懒加载(预加载)
懒加载字面意思就是当需要的时候才会去加载,不需要就不要加载。
以前处理 Fragment 的懒加载,我们通常会在 Fragment 中处理 setUserVisibleHint + onHiddenChanged
这两个函数,而在 Androidx
模式下,我们可以使用 FragmentTransaction.setMaxLifecycle()
的方式来处理 Fragment
的懒加载。
fragment 生命周期:
onAttach
-> onCreate
-> onCreateView
-> onViewCreated
-> onActivityCreated
-> onStart
-> onResume
一般在 onCreate
方法中接收 bundle
中的数据,在 onCreateView
创建 view
初始化 布局。在 onActivityCreated
或者 onResume
做懒加载
传统模式
package com.zhaoyanjun.mode1
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
abstract class BaseFragment : Fragment() {
/**
* 用户是否可见
*/
protected var mIsVisibleToUser = false
/**
* view是否创建
*/
protected var mIsViewCreated = false
/**
* 是否是第一次加载
*/
protected var mIsFirstLoad = false
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mIsViewCreated = true
if (mIsVisibleToUser) {
firstLoad()
}
}
/**
* 懒加载模式下生效
*/
fun firstLoad() {
if (mIsFirstLoad) {
return
}
mIsFirstLoad = true
onFirstLoad()
}
/**
* 懒加载的时候调用
*/
open fun onFirstLoad() {
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
mIsVisibleToUser = isVisibleToUser
if (mIsVisibleToUser && mIsViewCreated) {
firstLoad()
}
}
override fun onDestroyView() {
mIsVisibleToUser = false
mIsViewCreated = false
mIsFirstLoad = false
super.onDestroyView()
}
}
使用 :
package com.zhaoyanjun.mode1
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.zhaoyanjun.R
class ContentFragment : BaseFragment() {
private var param1: String? = null
private var rootView: View? = null
private var nameTv: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
rootView = inflater.inflate(R.layout.fragment_content, container, false)
nameTv = rootView?.findViewById(R.id.name)
return rootView
}
//懒加载更新数据
override fun onFirstLoad() {
super.onFirstLoad()
//第一次加载
Log.d("zhaoyanjun-", "firstLoad index: $param1")
nameTv?.text = param1
}
companion object {
private const val ARG_PARAM1 = "param1"
@JvmStatic
fun newInstance(param1: String) =
ContentFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
}
Androidx
在使用 Androidx 的时候,会发现 FragmentPagerAdapter(fragmentManager) 方法过时了
取而代之的是 两个参数的构造函数 。
public FragmentPagerAdapter(@NonNull FragmentManager fm,
@Behavior int behavior) {
mFragmentManager = fm;
mBehavior = behavior;
}
mBehavior 有两个值:BEHAVIOR_SET_USER_VISIBLE_HINT
、BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
。 默认情况下使用的是 BEHAVIOR_SET_USER_VISIBLE_HINT
从官方的注释声明中,我们能得到如下两条结论:
- 如果 behavior 的值为
BEHAVIOR_SET_USER_VISIBLE_HINT
,那么当 Fragment 对用户的可见状态发生改变时,setUserVisibleHint
方法会被调用。 - 如果 behavior 的值为
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
,那么当前选中的Fragment
在Lifecycle.State#RESUMED
状态 ,其他不可见的Fragment
会被限制在Lifecycle.State#STARTED
状态。
所以我的的懒加载方案就呼之欲出了:
package com.zhaoyanjun.mode2
import androidx.fragment.app.Fragment
abstract class BaseFragment2 : Fragment() {
private var isLoaded = false
override fun onResume() {
super.onResume()
//增加了Fragment是否可见的判断
if (!isLoaded && !isHidden) {
isLoaded = true
onFirstLoad()
}
}
override fun onDestroyView() {
super.onDestroyView()
isLoaded = false
}
open fun onFirstLoad() {
}
}
使用:
class ContentFragment2 : BaseFragment2() {
private var param1: String? = null
private var rootView: View? = null
private var nameTv: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
rootView = inflater.inflate(R.layout.fragment_content, container, false)
nameTv = rootView?.findViewById(R.id.name)
return rootView
}
override fun onFirstLoad() {
super.onFirstLoad()
//第一次加载
Log.d("zhaoyanjun-mode2 ", "firstLoad index: $param1")
nameTv?.text = param1
}
companion object {
private const val ARG_PARAM1 = "param1"
@JvmStatic
fun newInstance(param1: String) =
ContentFragment2().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}