什么是懶加載?為什么要用懶加載?###
1、什么是懶加載
懶加載就是當ViewPager和Fragment結合在一起使用時,Fragment呈現在用戶面前時才加載數據,當其從未被呈現在用戶面前時,不會執行加載數據的代碼。這就是我所理解的懶加載。
2、為什么要用懶加載
ViewPager默認會預加載下一頁,對于某些重量級的Fragment來說無疑會造成很大的開銷,當然了,如果對于你來說這些開銷是必要的,也不必無腦用懶加載。
背景簡介
很多時候我們都會將ViewPager和Fragment結合在一起使用,因為Android給我們提供了非常便利的FragmentPageAdapter,而這個adapter實現起來非常簡單:
public class TechFragmentPageAdapter extends FragmentPagerAdapter {private List<Fragment> fragmentList;public TechFragmentPageAdapter(FragmentManager fm, List<Fragment> fragmentList) {super(fm);this.fragmentList = fragmentList;}@Overridepublic Fragment getItem(int position) {return fragmentList.get(position);}@Overridepublic int getCount() {return fragmentList.size();}
}
復制代碼
現在我們一般的Activity都是繼承于AppCompatActivity,而這個activity可以
getSupportFragmentManager();
復制代碼
那么在實現以上的adapter時我們只要傳入我們的fragmentList就可以了。這樣的adapter既看起來舒服,又好使。但是ViewPager默認會加載下一頁,當你調用setOffscreenPageLimit(),并且將值設置為0,抱歉,沒啥用,因為當你設置的值小于1的時候默認還是1。那么,這個時候就需要我們自己去實現懶加載了。
實現
實現懶加載的關鍵是在于以下兩個方法:
/*** 文檔對于這個方法的描述是:Set a hint to the system about whether this * fragment's UI is currently visible to the user.**/
getUserVisibleHint()
setUserVisibleHint(boolean isVisibleToUser)
復制代碼
接下來讓我通過一段Log來了解這段故事,因為代碼結構比較簡單,只放其中的一段代碼上來,其他的,靠我們腦補就行了。
public class FirstFragment extends Fragment {private static final String TAG = "FirstFragment";@Overridepublic void onAttach(Context context) {Log.e(TAG, "onAttach");super.onAttach(context);}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {Log.e(TAG, "onCreate");super.onCreate(savedInstanceState);}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {Log.e(TAG, "onCreateView");return super.onCreateView(inflater, container, savedInstanceState);}@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {Log.e(TAG, "onActivityCreated");super.onActivityCreated(savedInstanceState);}@Overridepublic void onStart() {Log.e(TAG, "onStart");super.onStart();}@Overridepublic void onResume() {Log.e(TAG, "onResume");super.onResume();}@Overridepublic void onPause() {Log.e(TAG, "onPause");super.onPause();}@Overridepublic void onStop() {Log.e(TAG, "onStop");super.onStop();}@Overridepublic void onDestroyView() {Log.e(TAG, "onDestroyView");super.onDestroyView();}@Overridepublic void onDestroy() {Log.e(TAG, "onDestroy");super.onDestroy();}@Overridepublic void onDetach() {Log.e(TAG, "onDetach");super.onDetach();}@Overridepublic boolean getUserVisibleHint() {Log.e(TAG, "getUserVisibleHint");return super.getUserVisibleHint();}@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);Log.e(TAG, "setUserVisibleHint:" + isVisibleToUser);}
}復制代碼
非常簡單的一個Fragment,我只是在其中的各個方法中加入了Log這個操作而已,為了方便查看我使用了e這個級別的日志。類似的Fragment還有SecondFragment和ThirdFragment。當我使用FragmentPagerAdapter和ViewPager的時候,他們的Log輸出如下:
首先和我們預料的一樣,ViewPager的確有加載下一頁的特性,然后我們滑動到第二頁查看Log。
** 當前頁面不可見,但是ViewPager預加載的時候,我們判斷當前頁面是否可見,不可見則不進行加載數據的操作,僅僅做布局初始化的工作。在當前頁面變為可用的時候,我們調用加載數據的方法,那么數據便在ViewPager滑動到當前頁面的時候開始加載了。**
以下是我封裝的代碼,我封裝無力,各位如果覺得可以便自取,如果覺得不行可以自己改進~
package com.lauren.simplenews.news.widget;import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;/*** Created by Luo_xiasuhuei321@163.com on 2016/8/29.** 實現懶加載的Fragment*/
public abstract class BaseLazyFragment extends Fragment {protected View mRootView;protected Context mContext;protected boolean isVisible;private boolean isPrepared;private boolean isFirst = true;//--------------------system method callback------------------------//@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);isPrepared = true;initPrepare();}@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);if(getUserVisibleHint()){isVisible = true;lazyLoad();}else{isVisible = false;onInvisible();}}@Overridepublic void onResume() {super.onResume();if(getUserVisibleHint()){setUserVisibleHint(true);}}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);mContext = getActivity();}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {if(mRootView == null){mRootView = initView(inflater,container,savedInstanceState);}return mRootView;}//--------------------------------method---------------------------///*** 懶加載*/protected void lazyLoad(){if(!isPrepared || !isVisible || !isFirst){return;}initData();isFirst = false;}//--------------------------abstract method------------------------///*** 在onActivityCreated中調用的方法,可以用來進行初始化操作。*/protected abstract void initPrepare();/*** fragment被設置為不可見時調用*/protected abstract void onInvisible();/*** 這里獲取數據,刷新界面*/protected abstract void initData();/*** 初始化布局,請不要把耗時操作放在這個方法里,這個方法用來提供一個* 基本的布局而非一個完整的布局,以免ViewPager預加載消耗大量的資源。*/protected abstract View initView(LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState);
}
復制代碼
###后話### 最近我搭建了自己的個人博客,雖然今天(9.2)沒時間完善了,但是以后有空我會完善一下的。而且有些文章我也不會再簡書更新……比如我想把我的java回爐重造一下……但是有關java的這些東西不怎么想放到簡書上,還是放到我自己的小窩里~
最后附上鏈接吧:https://xiasuhuei321.github.io 恩,域名暫時沒買,先就這么用著吧。