ViewPager+Fragment懒加载
原文鏈接:http://blog.csdn.net/linglongxin24/article/details/53205878
Android中ViewPager+Fragment取消(禁止)預加載延遲加載(懶加載)問題解決方案
在Android中我們經(jīng)常會用到ViewPager+Fragment組合。然而,有一個很讓人頭疼的問題就是,我們去加載數(shù)據(jù)的時候由于ViewPager的內部機制所限制,所以它會默認至少預加載一個。這讓人很郁悶,所以,我就想到要封裝一個Fragment來解決這個問題。
這里還解決一個問題就是在Android酷炫歡迎頁播放視頻,仿螞蜂窩自由行和慕課網(wǎng),這里感謝有一位網(wǎng)友提出了bug,就是在播放視頻的時候如果滑動到第二頁和第三頁,第一頁的視頻還在播放,這是個讓人很頭疼的問題,在這里也完美解決。
1.問題初探
文章開始已經(jīng)說過ViewPager的預加載機制。那么,我們可不可以設置ViewPager的預加載為0,不就解決問題了嗎?
vp.setOffscreenPageLimit(0);經(jīng)過測試發(fā)現(xiàn),根本不是這么回事,為什么呢?我們來看看Viewpager的setOffscreenPageLimit()方法的源碼
private static final int DEFAULT_OFFSCREEN_PAGES = 1;/*** Set the number of pages that should be retained to either side of the* current page in the view hierarchy in an idle state. Pages beyond this* limit will be recreated from the adapter when needed.** <p>This is offered as an optimization. If you know in advance the number* of pages you will need to support or have lazy-loading mechanisms in place* on your pages, tweaking this setting can have benefits in perceived smoothness* of paging animations and interaction. If you have a small number of pages (3-4)* that you can keep active all at once, less time will be spent in layout for* newly created view subtrees as the user pages back and forth.</p>** <p>You should keep this limit low, especially if your pages have complex layouts.* This setting defaults to 1.</p>** @param limit How many pages will be kept offscreen in an idle state.*/public void setOffscreenPageLimit(int limit) {if (limit < DEFAULT_OFFSCREEN_PAGES) {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();}}我們發(fā)現(xiàn),即使你設置為0,那么還是會在里面判斷后設為默認值1。所以這個方法是行不通的。
2.問題再探
我們發(fā)現(xiàn)Fragment中有一個setUserVisibleHint(boolean isVisibleToUser)方法,這個方法就是告訴用戶,UI對用戶是否可見,那么我們在這里去加載數(shù)據(jù)會怎么樣呢?
這又是為什么呢?
因為ViewPager會加載好多Fragment,為了節(jié)省內容等會在Fragment不可見的某個時候調用onDestroyView()將用戶界面銷毀掉但是Fragment的實例還在,所以可能第一次加載沒有問題,
但是再次回到第一個Fragment再去加載的時候就會出現(xiàn)UI對用戶可見但是視圖還沒有初始化。
3.最終解決方案
package cn.bluemobi.dylan.viewpagerfragmentlazyload;import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast;/*** Fragment預加載問題的解決方案:* 1.可以懶加載的Fragment* 2.切換到其他頁面時停止加載數(shù)據(jù)(可選)* Created by yuandl on 2016-11-17.* blog :http://blog.csdn.net/linglongxin24/article/details/53205878*/public abstract class LazyLoadFragment extends Fragment {/*** 視圖是否已經(jīng)初初始化*/protected boolean isInit = false;protected boolean isLoad = false;protected final String TAG = "LazyLoadFragment";private View view;@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {view = inflater.inflate(setContentView(), container, false);isInit = true;/**初始化的時候去加載數(shù)據(jù)**/isCanLoadData();return view;}/*** 視圖是否已經(jīng)對用戶可見,系統(tǒng)的方法*/@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);isCanLoadData();}/*** 是否可以加載數(shù)據(jù)* 可以加載數(shù)據(jù)的條件:* 1.視圖已經(jīng)初始化* 2.視圖對用戶可見*/private void isCanLoadData() {if (!isInit) {return;}if (getUserVisibleHint()) {lazyLoad();isLoad = true;} else {if (isLoad) {stopLoad();}}}/*** 視圖銷毀的時候講Fragment是否初始化的狀態(tài)變?yōu)閒alse*/@Overridepublic void onDestroyView() {super.onDestroyView();isInit = false;isLoad = false;}protected void showToast(String message) {if (!TextUtils.isEmpty(message)) {Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();}}/*** 設置Fragment要顯示的布局** @return 布局的layoutId*/protected abstract int setContentView();/*** 獲取設置的布局** @return*/protected View getContentView() {return view;}/*** 找出對應的控件** @param id* @param <T>* @return*/protected <T extends View> T findViewById(int id) {return (T) getContentView().findViewById(id);}/*** 當視圖初始化并且對用戶可見的時候去真正的加載數(shù)據(jù)*/protected abstract void lazyLoad();/*** 當視圖已經(jīng)對用戶不可見并且加載過數(shù)據(jù),如果需要在切換到其他頁面時停止加載數(shù)據(jù),可以覆寫此方法*/protected void stopLoad() {}} }4.用法
LazyLoadFragment是一個抽象類,可以作為BaseFragment,繼承它。
(1).用setContentView()方法去加載要顯示的布局
(2).lazyLoad()方法去加載數(shù)據(jù)
(3).stopLoad()方法可選,當視圖已經(jīng)對用戶不可見并且加載過數(shù)據(jù),如果需要在切換到其他頁面時停止加載數(shù)據(jù),可以覆寫此方法
package cn.bluemobi.dylan.viewpagerfragmentlazyload;import android.util.Log;/** * Created by yuandl on 2016-11-17. */public class Fragment1 extends LazyLoadFragment {@Overridepublic int setContentView() {return R.layout.fm_layout1;}@Overrideprotected void lazyLoad() {String message = "Fragment1" + (isInit ? "已經(jīng)初始并已經(jīng)顯示給用戶可以加載數(shù)據(jù)" : "沒有初始化不能加載數(shù)據(jù)")+">>>>>>>>>>>>>>>>>>>";showToast(message);Log.d(TAG, message);}@Overrideprotected void stopLoad() {Log.d(TAG, "Fragment1" + "已經(jīng)對用戶不可見,可以停止加載數(shù)據(jù)");} }5.看效果界面
6.GitHub
總結
以上是生活随笔為你收集整理的ViewPager+Fragment懒加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ViewPager加载页面出现空白
- 下一篇: ListView和RecyclerVie