不知道你們使用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被緩存的時間是否超過一定的值,如果超過,再進行網絡請求刷新數據。我覺得這樣會更好。謝謝~晚安了,各位!