目录
1.FragmentStatePagerAdapter构造函数behavior参数设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
2.定义LazyResumeFragment,子fragment继承他进行管理即可
面临的问题:
TabLayout+ViewPager+FragmentStateAdapter是很常见的页面布局, 很多页面可以集中在一起,不断切换便能集中很多业务,但是面临一些问题:
- 多个页面,如果有缓存,将会本地缓存很多数据,造成卡顿等;
- 多个页面初始化,会出现大量请求,造成流量浪费;
简单来说就是,孙然我们滑动到了一个页面,但是viewPager两边的页面被加载了;
我们的预期是:
- 只有fragment看到的时候才会加载页面,而且只有第一次看到的时候才会加载数据
- 已经加载过的页面不会重复加载
直接上我已经测试的方案:
首先
1.FragmentStatePagerAdapter构造函数behavior参数设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
此种模式是官方推荐的模式,设置后,fragment可见和不可见只会走onResume和onPause函数,而不会走setUserVisibleHint
TestFragmentStatePagerAdapter.kt
class TestFragmentStatePagerAdapter(var titles:List<String> = ArrayList<String>(),var fragments:List<Fragment> = ArrayList<Fragment>(),var fm: FragmentManager): FragmentStatePagerAdapter(fm,
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getCount(): Int {
return fragments.size
}
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getPageTitle(position: Int): CharSequence? {
return titles[position]
}
}
2.定义LazyResumeFragment,子fragment继承他进行管理即可
LazyResumeFragment.kt
/***
* 针对设置了BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式的fragment
* create by DragonForest on 2022/3/15
*/
abstract class LazyResumeFragment : Fragment() {
private var mView: View? = null
private val TAG = this.javaClass.simpleName
private var isFirstShow = true
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (mView == null) {
mView = LayoutInflater.from(context).inflate(getLayoutRes(), container, false)
}
initView()
return mView
}
override fun onDestroyView() {
super.onDestroyView()
isFirstShow = true
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
Log.i(TAG,"setUserVisibleHint,isVisibleToUser:$isVisibleToUser ")
}
override fun onResume() {
super.onResume()
Log.i(TAG,"onResume")
if (isFirstShow) {
isFirstShow = false
initLoadData()
}
onVisible()
}
override fun onPause() {
super.onPause()
Log.i(TAG,"onPause")
onInVisible()
}
override fun onAttach(context: Context) {
super.onAttach(context)
Log.i(TAG,"onAttach")
}
override fun onDetach() {
super.onDetach()
Log.i(TAG,"onDetach")
}
/**
* 获取资源文件
*/
abstract fun getLayoutRes(): Int
/**
* 初始化view
*/
abstract fun initView()
/**
* 初始化数据
* 初次请求接口加载数据请在这里写
*/
abstract fun initLoadData()
/**
* fragment显示在前台时
*/
abstract fun onVisible()
/**
* fragment隐藏时
*/
abstract fun onInVisible()
}
子fragment:
/***
* create by DragonForest on 2022/3/15
*/
class HomeFragment1: LazyVisibleHintFragment() {
val TAG = this.javaClass.simpleName
val uiHandler: Handler = Handler(Looper.getMainLooper())
override fun getLayoutRes(): Int {
return R.layout.fragment_home1
}
override fun initView() {
Log.i(TAG,"initView")
tv_loading?.text = "未初始化"
iv_result?.visibility = View.GONE
}
override fun initLoadData() {
Log.i(TAG,"initLoadData")
tv_loading?.text = "正在加载..."
iv_result?.visibility = View.GONE
uiHandler.postDelayed({
tv_loading?.text = "加载完成"
iv_result?.visibility = View.VISIBLE
},2000L)
}
override fun onVisible() {
Log.i(TAG,"onVisible")
}
override fun onInVisible() {
Log.i(TAG,"onInVisible")
}
}
3.使用:
class FragmentTestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment_test)
initView()
}
private fun initView() {
var titles = arrayOf("首页1","首页2","首页3","首页4")
var fragments = arrayOf(HomeFragment1(),HomeFragment2(),HomeFragment3(),HomeFragment4())
viewPager.adapter = TestFragmentStatePagerAdapter(titles.toList(),fragments.toList(),supportFragmentManager)
tablayout.setupWithViewPager(viewPager)
}
}
这样一个懒加载的案例就完成了;
总结:
- 在BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式下可以控制fragment可见和不可见只会调用onResume和onPause, 实现懒加载比较容易; 如果设置成BEHAVIOR_SET_USER_VISIBLE_HINT, setUserVisibleHint将会被调用,需要特殊处理,建议在新建一个LazyVisibleHintFragment基类来管理;
建议最好使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式, 因为BEHAVIOR_SET_USER_VISIBLE_HINT已经被官方废弃, 而且适配这种模式的懒加载较复杂,会背离fragment设计初衷,比如onResume中本来就是用来显示页面的
- 本次只处理了fragment在viewPager中的懒加载, 因为这是最常见的; 还有几种场景,比如show,add时候的懒加载,嵌套fragment的懒加载