1.什麼是fragment懶加載以及爲什麼要使用fragment懶加載。
先看下Demo實現的效果吧。大家對這種效果一定不陌生,知乎,掘金等app都用到了這種效果。
這裏探索的懶加載是當viewpager
結合tablayout
時,多個fragment
在進行數據加載的時候,當且僅當fragment
對用戶可見的時候,才進行數據加載,這裏的數據加載可以是網絡請求,數據庫請求,是需要消耗資源的,如果不使用懶加載,對於那些用戶未打開的頁面,由於viewpager
的加載機制,即使用戶未打開的fragment
也有可能進行數據加載,造成資源白白的浪費,因此爲了良好的用戶體驗,懶加載是有必要的。
2.fragment懶加載的實現方式以及封裝。
fragment
懶加載實現的關鍵在於其的setUserVisibleHint(isVisibleToUser: Boolean)
方法,該方法在fragment
對用戶由可見變爲不可見以及由不可見變爲可見時都會回調。我們創建抽象AbstractLazyInitFrag
,對其進行封裝。首先我們引入isVisibleToUser
變量,負責保存當前fragment
對用戶的可見狀態。同時還有幾個值得注意的地方:
-
setUserVisibleHint(isVisibleToUser: Boolean)
方法的回調時機並沒有與fragment
的生命週期有確切的關聯,比如說,回調時機有可能在onCreateView
方法之後,也可能在onCreateView
方法之前。因此,必須引入一個標誌位isPrepareView
判斷view
是否創建完成,不然,很容易會造成空指針異常。我們初始化該變量爲false,在onViewCreated
中,也就是view
創建完成後,將其賦值爲true
。代碼中是這樣:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isPrepareView = true
}
- 數據初始化只應該加載一次,因此,引入第二個標誌位,
isInitData
,初始爲false,在數據加載完成之後,將其賦值爲true
。至此,我們的懶加載方法考慮了所有條件。也就是當isVisibleToUser
爲true
,isInitData
爲false
,isPrepareView
爲true
時,進行數據加載,並且加載後爲了防止重複調用,將isInitData
賦值爲true
。代碼如下:
private fun lazyInitData() {
if (!isInitData && isVisibleToUser && isPrepareView) {
isInitData = true
initData()
}
}
其中initData()
爲抽象方法,由子類實現,在這裏操作數據加載的邏輯。
- 該方法的調用時機。首先是
setUserVisibleHint(isVisibleToUser: Boolean)
方法中是必須調用的。代碼如下:
/*當fragment由可見變爲不可見和不可見變爲可見時回調*/
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
this.isVisibleToUser = isVisibleToUser //標誌位保存fragment對用戶的可見狀態
lazyInitData()
}
其次,很容易忽略的一點。對於上圖中第一個fragment
,如果setUserVisibleHint(isVisibleToUser: Boolean)
方法在onCreateView
之前調用的話,如果懶加載方法只在setUserVisibleHint(isVisibleToUser: Boolean)
中調用,那麼該fragment將只能在被主動切換一次之後才能加載數據,這肯定是不可能的,因此,我們需要在view
創建完成之後,也進行一次調用。思來想去,在onActivityCreated
方法中是最合適的。我們在繼承的時候,在onViewCreated
方法中進行一些初始化就行了,這樣不會引起衝突。代碼如下:
/*fragment生命週期中onViewCreated之後的方法 在這裏調用一次懶加載 避免第一次可見不加載數據*/
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
lazyInitData()
}
貼上完整的封裝好的抽象基類fragment:
abstract class AbstractLazyInitFrag : Fragment() {
private var isInitData = false /*標誌位 判斷數據是否初始化*/
private var isVisibleToUser = false /*標誌位 判斷fragment是否可見*/
private var isPrepareView = false /*標誌位 判斷view已經加載完成 避免空指針操作*/
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(getLayoutId(), container, false)
}
abstract fun getLayoutId(): Int
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isPrepareView = true
}
/*加載數據的方法,由子類實現*/
abstract fun initData()
/*懶加載方法*/
private fun lazyInitData() {
if (!isInitData && isVisibleToUser && isPrepareView) {
isInitData = true
initData()
}
}
/*當fragment由可見變爲不可見和不可見變爲可見時回調*/
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
this.isVisibleToUser = isVisibleToUser
lazyInitData()
}
/*fragment生命週期中onViewCreated之後的方法 在這裏調用一次懶加載 避免第一次可見不加載數據*/
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
lazyInitData()
}
}
順便貼下Demo中測試的繼承的子類:
class FragLazyInitTest : AbstractLazyInitFrag() {
private val dataList = ArrayList<String>()
private val adapter = ListAdapter(dataList)
/*初始化一般在這裏實現*/
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = adapter
}
override fun getLayoutId(): Int {
return R.layout.frag_lazy_init_test
}
override fun initData() {
/*模擬的加載數據過程,實際場景一般是網絡請求或者數據庫等耗時操作*/
swipeRefreshLayoutFLIT.isRefreshing = true
swipeRefreshLayoutFLIT.postDelayed({
swipeRefreshLayoutFLIT.isRefreshing = false
dataList.add("data1")
dataList.add("data2")
dataList.add("data3")
dataList.add("data4")
dataList.add("data5")
dataList.add("data6")
dataList.add("data7")
dataList.add("data8")
adapter.notifyDataSetChanged()
}, 2000)
}
}
3.Demo地址
學習分享,共勉
題外話,我從事Android開發已經五年了,此前我指導過不少同行。但很少跟大家一起探討,正好最近我花了一個多月的時間整理出來一份包括不限於高級UI、性能優化、移動架構師、NDK、混合式開發(ReactNative+Weex)微信小程序、Flutter等全方面的Android進階實踐技術,今天暫且開放給有需要的人,若有關於此方面可以轉發+關注+點贊後加羣 878873098 領取,或者評論與我一起交流探討。
資料免費領取方式:轉發+關注+點贊後,加入點擊鏈接加入羣聊:Android高級開發交流羣(878873098)即可獲取免費領取方式!
重要的事說三遍,關注!關注!關注!