引言
TabLayout+ViewPager+Fragment是我们很常用的页面导航布局,通过Tab选中与否切换fragment页面,但由于ViewPager的缓存机制,会默认加载当前fragment相邻的两个fragment的数据。这有时候并不符合我们的业务需求,因此需要对fragment做懒加载,让其在点击tab切换fragment时(也就是当前fragment对用户可见的时候)只加载该页面数据。
验证
在未进行懒加载时,我们会发现在第一个Fragment可见的时候(此时未切换到第二个Tab栏),此时第二个Fragment的生命周期被调用情况如下:
增加这个setUserVisibleHint方法的log打印:
结论
onResume在Fragment中表示当前Fragment针对用户来说是否可见,但是由于ViewPager的缓存机制,观察生命周期,此方法已经没有意义了。
从Fragment1切换到Fragment2的log打印:
可以看出onResume方法并不决定布局是否可见,而是由setUserVisibaleHint方法的返回值来确定的。
那个Fragment的该方法返回true则Tab切换到哪个Fragment上。
因此需要在setUserVisibleHint中的参数为true的时候再去做数据加载
完整版的懒加载BaseFragment代码:
/**
* @data on 4/28/21 9:58 AM
* @auther KC
* @describe BaseFragment,实现了Fragment懒加载
*/
open class BaseFragment : Fragment() {
//表明fragment是否显示
private var mIsVisibleToUser = false
//表明view是否被加载
private var mIsViewCreatetd = false
//表明data是否被加载
private var mIsDataLoaded = false
/**
* 是否view已被加载
*/
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mIsViewCreatetd = true
}
/**
* 懒加载的关键
* isVisibleToUser是否为true,则对应表明页面是否展示到当前Fragment。
*/
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
mIsVisibleToUser = isVisibleToUser
lazyLoad()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (mIsVisibleToUser && !mIsDataLoaded) {
lazyLoad()
}
}
/**
* view和data清除
*/
override fun onDestroyView() {
super.onDestroyView()
mIsViewCreatetd = false
mIsDataLoaded = false
}
fun lazyLoad() {
if (mIsViewCreatetd && mIsVisibleToUser && !mIsDataLoaded) {
initData()
mIsDataLoaded = true
}
}
//开放要加载的数据
open fun initData() {}
}
四个Fragment的代码雷同,只是tagStr改变了个序号
class Fragment1 : BaseFragment() {
val tagStr = "Fragment1"
val vBinding by lazy {
Fragment1Binding.inflate(layoutInflater)
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
logd(tagStr,"setUserVisibleHint 返回 $isVisibleToUser")
}
override fun onAttach(context: Context) { //对应onDetach()
super.onAttach(context)
logd(tagStr,"onAttach")
}
override fun onCreate(savedInstanceState: Bundle?) { //对应onDestroy()
super.onCreate(savedInstanceState)
logd(tagStr,"onCreate")
}
override fun onCreateView( //对应onDestroyView()
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
logd(tagStr,"onCreateView")
return vBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) { //无对应方法
super.onActivityCreated(savedInstanceState)
logd(tagStr,"onActivityCreated")
}
override fun onStart() { //对应onStop()
super.onStart()
logd(tagStr,"onStart")
}
override fun onResume() { //对应onPause()
super.onResume()
logd(tagStr,"onResume")
}
override fun onPause() {
super.onPause()
logd(tagStr,"onPause")
}
override fun onStop() {
super.onStop()
logd(tagStr,"onStop")
}
override fun onDestroyView() {
super.onDestroyView()
logd(tagStr,"onDestroyView")
}
override fun onDestroy() {
super.onDestroy()
logd(tagStr,"onDestroy")
}
override fun onDetach() {
super.onDetach()
logd(tagStr,"onDetach")
}
override fun initData() {
super.initData()
toast("$tagStr 加载数据...")
}
}
最后,附上Activity和PublicTabAdapter的代码:
Activity代码:
class Kotlin18 : AppCompatActivity() {
val vBinding by lazy {
ActivityKotlin18Binding.inflate(layoutInflater)
}
val fragments = ArrayList<Fragment>()
val titles = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(vBinding.root)
setTabLayout()
}
//设置TabLayout和ViewPager
fun setTabLayout(){
setTitleData()
titles.forEach {
vBinding.tabLayout.addTab(vBinding.tabLayout.newTab().setText(it))
}
fragments.add(Fragment1())
fragments.add(Fragment2())
fragments.add(Fragment3())
fragments.add(Fragment4())
vBinding.viewPager.adapter = PublicTabAdapter(supportFragmentManager,fragments,titles)
vBinding.tabLayout.setupWithViewPager(vBinding.viewPager)
}
//设置tabTitles数据
fun setTitleData(){
titles.add("Tab1")
titles.add("Tab2")
titles.add("Tab3")
titles.add("Tab4")
}
}
PublicTabAdpter代码:
/**
* @data on 4/23/21 9:35 PM
* @auther KC
* @describe TabLayout+ViewPager适配器
*/
class PublicTabAdapter(fm: FragmentManager?,
private val list_fragment: ArrayList<Fragment>,
private val list_Title: ArrayList<String>) : FragmentPagerAdapter(fm!!) {
override fun getItem(position: Int): Fragment {
return list_fragment[position]
}
override fun getCount(): Int {
return list_fragment.size
}
// 此方法用来显示tab上的名字
override fun getPageTitle(position: Int): CharSequence? {
return list_Title[position % list_Title.size]
}
}