在Android開發中常常會使用到ViewPager, ViewPager若是和Fragment一塊兒使用的話, 就要考慮懶加載和預加載的問題. ViewPager有個方法setOffscreenPageLimit 這個方法能夠配置緩存數量. 那是否是直接設置0就能夠實現懶加載了呢? 不是的, 查看源碼:git
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) { //DEFAULT_OFFSCREEN_PAGES爲1
Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
+ DEFAULT_OFFSCREEN_PAGES);
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
populate();
}
}
複製代碼
設置0後會無效的, limit 仍是被設置成默認的1github
懶加載就是當用戶滑動到當前的frament才能去加載數據, 這樣避免加載了數據可是沒有使用到, 形成了浪費.
預加載是爲了提早加載數據, 讓用戶減小等待時間. 懶加載和預加載應該根據具體的業務要求去使用. 沒有誰好誰壞之分. 但二者的前提都是要搞清楚Fragment在ViewPager中的生命週期, 下面先來弄清楚生命週期的調用.緩存
首先寫一個簡單的Activity裏面有ViewPager 代碼以下:bash
public class MainActivity extends AppCompatActivity {
private ViewPager viewById;
private List<Fragment> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewById = findViewById(R.id.vp);
list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
SimpleFragment simpleFragment = SimpleFragment.newInstance(i);
list.add(simpleFragment);
}
MineAdapter mineAdapter = new MineAdapter(getSupportFragmentManager(),list);
viewById.setOffscreenPageLimit(1);
viewById.setAdapter(mineAdapter);
}
}
複製代碼
關於這個SimpleFragment代碼就不用貼出來了 很簡單就是在各個生命週期中加入log. 這個MineAdapter 很簡單的. 以下:網絡
public class MineAdapter extends FragmentPagerAdapter {
List<Fragment> mPages;
public MineAdapter(FragmentManager fm, List<Fragment> pages) {
super(fm);
mPages=pages;
}
@Override
public Fragment getItem(int i) {
return mPages.get(i);
}
@Override
public int getCount() {
return mPages.size();
}
}
複製代碼
運行程序 來看看Fragment生命週期 日誌以下: 爲了方便敘述第0個fragement簡稱爲0號. 這時候實際上是緩存數量爲1ide
經過以上的日誌 能夠總結關鍵幾點.ui
懶加載是滑動到當前Fragment的時候纔去調用的方法. 通常在實際業務中就是滑到了要展現的頁面去調接口獲取數據.
寫一個基礎的BaseLazyFragment , 繼承這個BaseLazyFragment 重寫lazyInit()方法. 這個方法裏寫你須要執行的懶加載操做.spa
public class BaseLazyFragment extends Fragment {
private boolean isViewPrepared; // 標識fragment視圖已經初始化完畢
private boolean hasFetchData; // 標識已經觸發過懶加載數據
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
lazyFetchDataIfPrepared(); //通過了預加載頁面, 而後展現
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewPrepared = true;
lazyFetchDataIfPrepared(); //首次進入, 沒有預加載直接加載數據
}
/**
* 懶加載方法,獲取數據什麼的放到這邊來使用,在切換到這個界面時才進行網絡請求
*/
private void lazyFetchDataIfPrepared() {
// 用戶可見fragment && 沒有加載過數據 && 視圖已經準備完畢
if (getUserVisibleHint() && !hasFetchData && isViewPrepared) {
hasFetchData = true; //已加載過數據
lazyInit();
}
}
/**
* 執行須要懶加載的方法
*/
protected void lazyInit() {
Log.i("zmin........." + getArguments().getInt("key"), ".............加載完成數據");
}
@Override
public void onDestroyView() {
super.onDestroyView();
hasFetchData = false;
isViewPrepared = false;
Log.i("zmin........." + getArguments().getInt("key"), ".............onDestroyView");
}
}
複製代碼
viewpager其實對預加載有很好的支持. 能夠直接調用方法setOffscreenPageLimit來設置緩存的數量.3d
在實際業務中, 可能存在這樣一種需求. 雖然是須要預加載的, 可是要監聽Fragment的可見狀態. 好比Fragment中有視頻播放. 若是Fragment可見的話就要播放. 不可見的時候就須要暫停. 這時候還須要考慮的是Fragment可能會跳轉到其餘界面. Fragment雖然可見和不可見有個生命週期方法setUserVisibleHint回調, 可是沒法直接得知當前狀態是一直不可見的,仍是由可見轉爲不可見的 . 下面來實現這個功能 :日誌
public class BaseAppearFragment extends Fragment {
private boolean isViewPrepared; // 標識fragment視圖已經初始化完畢
private boolean hasAppear; //標識界面當前可見
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//當前fragment轉爲可見狀態
if (isVisibleToUser && isViewPrepared && !hasAppear) {
onFragmentAppear();
hasAppear = true;
}
//當前fragment轉爲不可見狀態
if (!isVisibleToUser && hasAppear) {
onFragmentDismiss();
hasAppear = false;
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("zmin........." + getArguments().getInt("key"), ".............onCreateView");
return inflater.inflate(R.layout.activity_fragment, null);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewPrepared = true;
TextView tv = getView().findViewById(R.id.tv);
tv.setText(String.valueOf(getArguments().getInt("key")));
Log.i("zmin........." + getArguments().getInt("key"), ".............onViewCreated");
}
@Override
public void onResume() {
super.onResume();
Log.i("zmin........." + getArguments().getInt("key"), ".............onResume(");
if (getUserVisibleHint()) {
onFragmentAppear();
hasAppear = true;
}
}
@Override
public void onDestroyView() {
isViewPrepared = true;
super.onDestroyView();
Log.i("zmin........." + getArguments().getInt("key"), ".............onDestroyView");
}
/**
* 界面可見
*/
public void onFragmentAppear() {
Log.i("zmin........." + getArguments().getInt("key"), "......界面可見..onFragmentAppear");
}
/**
* 界面由可見轉爲不可見
*/
public void onFragmentDismiss() {
Log.i("zmin........." + getArguments().getInt("key"), "...由可見轉爲不可見.........onFragmentDismiss");
}
}
複製代碼
能夠看到主要在在setUserVisibleHint和onResume方法中作判斷. 由於Fragment切換的時候, 不少生命週期方法是不走的.
經過詳細的日誌 分析了Fragment生命週期的執行. 從而實現懶加載和預加載中對可見狀態監聽. 不少業務場景下須要用到. 若是要懶加載能夠直接繼承BaseLazyFragment 類便可. 若是要監聽可見隱藏狀態則能夠繼承 BaseAppearFragment . 若是還想本身去看看打印的日誌. 能夠clone代碼, github地址 github.com/zmin666/Zmi… 但願這些總結對你有幫助.