Fragment懒加载,就是在Fragment可见的时候才加载数据,而不是在创建时加载数据,假设一个页面有多个Fragment,如果每个Fragment都在创建后发送网络请求加载数据,那势必会增加一些不必要的流量消耗。使用懒加载的好处就是节省流量,使用也更加合理。
实现懒加载其实很简单,在使用FragmentPagerAdapter或FragmentStatePagerAdapter时使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT标识,之后Fragment在可见时都会调用onResume()方法,不可见时会调用onPause()方法,因此在onResume()中拉取数据就可以实现懒加载了。
具体来说,可以定义一个方法loadData加载数据,同时可以配置一个参数needLazyLoadData表示是否需要懒加载,如果需要,则在onResume中请求数据;如果不需要,则在onViewCreated请求数据,这样在页面创建时就直接加载数据了。代码如下:
open class BaseFragment : Fragment() {
companion object {
private const val TAG = "BaseFragment"
}
protected var hasDataLoaded = false //是否加载过数据,不管加载成功或失败
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.i(TAG, "${javaClass.simpleName} onViewCreated")
if (!needLazyLoadData()) {
Log.i(TAG, "${javaClass.simpleName} 正在加载数据(非懒加载)")
loadData()
}
}
override fun onResume() {
super.onResume()
Log.i(TAG, "${javaClass.simpleName} onResume")
if (needLazyLoadData() && !hasDataLoaded) {
Log.i(TAG, "${javaClass.name} 正在加载数据(懒加载)")
loadData()
hasDataLoaded = true
}
}
override fun onPause() {
super.onPause()
Log.i(TAG, "${javaClass.simpleName} onPause")
}
//是否需要懒加载,返回true表示切换到页面时才会加载数据,主要用在ViewPager切换中,
//注意FragmentPagerAdapter使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
protected open fun needLazyLoadData() = true
//加载数据
protected open fun loadData() {
}
}
代码很少,这样子就能实现懒加载了,同时也可以灵活配置页面是使用懒加载方式还是非懒加载方式加载数据,具体使用如下:
新建三个Fragment继承至BaseFragment,FirstFragment、SecondFragment、ThirdFragment,其中FirstFragment、SecondFragment实现懒加载,而ThirdFragment在创建页面时就加载数据,通过tv.postDelayed延迟2秒显示模拟网络请求数据的过程。
class FirstFragmnet : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_test, container, false)
}
override fun needLazyLoadData() = true
override fun loadData() {
//模拟加载数据
tv.text = "正在加载数据"
tv.postDelayed({
tv.text = "我是FirstFragmnet\n点击跳转测试单个Fragment"
tv.setOnClickListener {
startActivity(Intent(context, FirstActivity::class.java))
}
}, 2000) //延迟2秒后显示
}
}
class SecondFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_test, container, false)
}
override fun needLazyLoadData() = true
override fun loadData() {
//模拟加载数据
tv.text = "正在加载数据"
tv.postDelayed({
tv.text = "我是SecondFragment"
}, 2000) //延迟2秒后显示
}
}
class ThirdFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_test, container, false)
}
override fun needLazyLoadData() = false
override fun loadData() {
//模拟加载数据
tv.text = "正在加载数据"
tv.postDelayed({
tv.text = "我是ThirdFragment"
}, 2000) //延迟2秒后显示
}
}
在MainActivity中使用ViewPager切换Fragment:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initViewPager()
}
private fun initViewPager() {
val titleList: MutableList<String> = mutableListOf("第一页", "第二页", "第三页")
val fragmentList: MutableList<Fragment> = mutableListOf(FirstFragmnet(), SecondFragment(), ThirdFragment())
//BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT是关键
view_pager.adapter = object : FragmentPagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getCount() = fragmentList.size
override fun getItem(position: Int) = fragmentList[position]
override fun getPageTitle(position: Int) = titleList[position]
}
view_pager.offscreenPageLimit = fragmentList.size - 1
tab_layout.setupWithViewPager(view_pager)
}
}
activity_main布局如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="@+id/tab_layout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:tabBackground="@android:color/darker_gray"
app:tabIndicatorColor="#F7F7F7"
app:tabIndicatorHeight="0dp"
app:tabRippleColor="@android:color/transparent" />
</androidx.constraintlayout.widget.ConstraintLayout>
最后看一下效果,可以看到当切换到SecondFragment时页面才开始加载数据,而切换到ThirdFragment时页面已经是加载完成的状态了。
源码地址
|