防止ViewPager和Fragment結合使用時候的數據預加載

不知道大家使用ViewPager和Fragment結合的時候發現一個問題沒,若是你的每一個Fragment都須要請求網絡數據,而且你在請求網絡數據的時候會加入進度對話框的加載顯示效果,當你顯示第一個Fragment的時候,進度對話框並非在你這個Fragment數據加載完成以後就中止顯示了,它會等待ViewPager預加載的Fragment數據也加載完成的時候纔會中止顯示,即你加載第一個Fragment數據時,進度對話框的顯示其實是兩個或者三個的層疊顯示。json

 

反正最近我是遇到這種狀況了,下面說說我怎麼解決的.緩存

 

ViewPager和Fragment結合使用的時候,有兩種適配器可使用,一個是FragmentStatePagerAdapter,一個是FragmentPagerAdapter。前者在內存中最多會保留三個Fragment實例,也就是說當有Fragment切換的時候,Fragment生命週期會走onDestroyView()-->onDestroy()方法,而後建立會走onCreate()-->onCreateView()方法。可是對於後者,內存中會保留全部建立後的Fragment,也就是說當Fragment切換的時候,生命週期會走onDestroyView()和onCreateView()方法,可是不會走onDestroy()和onCreate()方法。不論是哪種PagerAdapter,ViewPager都存在預加載Fragment的效果,爲了讓數據只有在Fragment顯示給用戶的時候纔去加載,咱們作了以下幾件事情:網絡

 

1.首先,在Fragment裏面有一個方法優化

public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);    }

須要注意的是這個方法會在Fragment的onCreate()方法調用以前就調用,這裏咱們在裏面做以下修改生命週期

public void setUserVisibleHint(boolean isVisibleToUser) {        if (isVisibleToUser && isVisible()){            initData();        }        super.setUserVisibleHint(isVisibleToUser);    }

initData()是加載數據的方法,不用管它。這裏isVisibleToUser,若是Fragment是顯示給用戶的,那麼這個值是true,isVisible()方法能夠判斷Fragment的視圖是否建立好,對於第一個顯示的Fragment,由於isVisibleToUSer是true,可是isVisible()是false,那麼在顯示第一個Fragment的時候是空白的。可是對於其它的Fragment,由於存在ViewPager的預加載,當顯示到Fragment的時候,isVisible()是true,而不是false。因此會在這個方法裏面進行加載數據的操做。內存

2.而後,咱們來解決第一個Fragment顯示空白的問題,我是在onCreateView()方法裏面進行數據的加載操做。而後,我在這個方法裏面進行以下的修改get

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        //...        if (getUserVisibleHint()){            initData();        }        return inflater.inflate(R.layout.fragment_blank, container, false);    }

這裏getUserVisibleHint()方法能夠判斷當前Fragment是不是顯示給用戶的,對於第一個Fragment,由於不會在setUserVisibleHint()方法裏面進行數據加載操做,當走到onCreateView()方法後,會在這裏判斷,因爲getUserVisibleHint()是true,因此會進行數據的加載。而後對於其它的Fragment來講,由於存在預加載的效果,當先走setUserVisibleHint()方法時,因爲isVisibleToUser是false,因此不會進行數據的加載,而走完這個方法到達onCreateView()方法時,getUserVisibleHint()返回的是false,因此也不會進行數據的加載,只有當切換到這個Fragment的時候,會去回調setUserVisibleHint()方法,在這個方法裏面進行了數據的加載操做。it

 

以上就解決了ViewPager和Fragment結合使用的時候數據的預加載。變量

 

3.其實,我以爲上面的作法並非完美,由於你會發現每次切換到Fragment的時候都會從新加載數據,這樣是很是耗流量的。因而乎,我就想了一個辦法,在Fragment裏面添加了一個long的變量,用來記錄Fragment刷新的時間fragment

private long refreshTime  = 0;

而後修改setUserVisibleHint()方法,以下所示

public void setUserVisibleHint(boolean isVisibleToUser) {        if (isVisibleToUser && isVisible()){            if (refreshTime == 0 ||(refreshTime != 0 && (System.currentTimeMillis()-refreshTime) > 30 * 60 * 1000)) {                initData();            }        }        super.setUserVisibleHint(isVisibleToUser);    }

即若是這個Fragment的View視圖沒有被銷燬的時候,只有當數據的時效性超過30min後再次切換到這個Fragment纔會進行數據的加載。

 

4.在每次進行數據加載操做的時候對這個時間刷新,在每次View視圖被從新建立的時候將時間置爲0,以下所示

private void initData(){    refreshTime=System.currentTimeMillis();}

 

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        refreshTime = 0;        //.......    }

 

好了,以上是關於我如何解決ViewPager和Fragment結合使用時候的數據預加載問題。其實咱們還能夠進行優化,對每一個Fragment獲取到的網絡數據(通常是json)進行緩存,當每次切換的時候,先去加載本地的json數據進行展現,再去判斷當前時間和這個json被緩存的時間是否超過必定的值,若是超過,再進行網絡請求刷新數據。我以爲這樣會更好。謝謝~晚安了,各位!

相關文章
相關標籤/搜索