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


不知道你們使用ViewPager和Fragment結合的時候發現一個問題沒,如果你的每個Fragment都需要請求網絡數據,並且你在請求網絡數據的時候會加入進度對話框的加載顯示效果,當你顯示第一個Fragment的時候,進度對話框並不是在你這個Fragment數據加載完成之后就停止顯示了,它會等待ViewPager預加載的Fragment數據也加載完成的時候才會停止顯示,即你加載第一個Fragment數據時,進度對話框的顯示實際上是兩個或者三個的層疊顯示。

 

反正最近我是遇到這種情況了,下面說說我怎么解決的.

 

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()方法里面進行數據的加載操作。然后,我在這個方法里面進行如下的修改

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()方法,在這個方法里面進行了數據的加載操作。

 

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

 

3.其實,我覺得上面的做法並不是完美,因為你會發現每次切換到Fragment的時候都會重新加載數據,這樣是非常耗流量的。於是乎,我就想了一個辦法,在Fragment里面添加了一個long的變量,用來記錄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被緩存的時間是否超過一定的值,如果超過,再進行網絡請求刷新數據。我覺得這樣會更好。謝謝~晚安了,各位!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM