關於android開發設置View Pager的直接跳轉頁set CurrentItem會阻塞主線程ANR。
根據網上解決的說法,分析源碼:
if (mFirstLayout) { // We don't have any idea how big we are yet and shouldn't have any pages either. // Just set things up and let the pending layout handle things. mCurItem = item; if (dispatchSelected) { dispatchOnPageSelected(item); } requestLayout(); } else { populate(item); scrollToItem(item, smoothScroll, velocity, dispatchSelected); }
是因為主線程測量滑動距離,繪制UI阻塞,因此通過反射拿到 mFirstLayout變量,每次在setCurrentItem的代碼之前設置為true,
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(vpImg, true);
vpImg.setCurrentItem(num + numCenter, false);
} catch (Exception e) {
e.printStackTrace();
}
根據以上解決方法本應能夠解決ANR,可事實依然存在問題,上碼:
@Override
public int getCount() {
tvPicSum.setText(vpImg.getCurrentItem() % mOrderListPic.size() +
1 + "/"
+ mOrderListPic.size());
if (mOrderListPic.size() >= 2) {// 當條目超過一個
return Integer.MAX_VALUE;
}
return mOrderListPic.size();
}
這是我的適配器PagerAdapter的getCount()方法,為了能夠實現ViewPager的近似無限輪播效果,我們將viewPager的限制頁數設置為Integer類型的最大值,但也從而會使ViewPager在setCurrentItem時測量頁數太大,繪制UI頻繁而阻塞主線程ANR,因此我將數量改成了相對較小些mOrderListPic.size()*40。問題便得帶了根本的解決。
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
項目需求有無限輪播圖,之前一直用的沒問題,就用之前的放上去了,但是,有個需求是刷新時,把輪播圖位置復位,心想不就是setCurrentItem么,so easy!
但....事情卻沒有那么簡單
大家都知道,無限輪播圖的做法就是把Adapter中重寫getCount返回一個很大的數字,欺騙viewpager有很多,在對position和數據size取模,使數據的position和實際的position對應上,然后使用的時候把當前position設置到getCount數值 的中間,所以setAdapter后setCurrentItem(...),ok,到這里一切順利
當頁面刷新時,得到新數據,對viewpager重新設置數據,然后再次setCurrentItem恢復到初始位置時,問題就來了,這時整個頁面完全卡死,過一會就ANR了
懵了......
這么簡單的問題竟然會有問題
好了,開始解決問題
經過調試,問題代碼就出現在setCurrentItem這行代碼,查看ViewPager源碼,發現最終調用到這個方法:
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {}方法里面有行判斷:
if (mFirstLayout) { // We don't have any idea how big we are yet and shouldn't have any pages either. // Just set things up and let the pending layout handle things. mCurItem = item; if (dispatchSelected) { dispatchOnPageSelected(item); } requestLayout(); } else { populate(item); scrollToItem(item, smoothScroll, velocity, dispatchSelected); }
mFirstLayout是一個私有變量,默認為true,第一次設置數據時,mFirstLayout為true,然后在viewpager的
onLayout方法中就被設置成了false
當下次再次setCurrentItem時就進入了else中,這時,else中的代碼就會引起UI卡頓,具體原因還未深入研究
但到這就有了思路了,可以利用反射,強行修改mFirstLayout的值為true
try { Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout"); mFirstLayout.setAccessible(true); mFirstLayout.set(vp_top, true); myPagerAdapter.notifyDataSetChanged(); vp_top.setCurrentItem(Integer.MAX_VALUE/4-( Integer.MAX_VALUE/4 % ids_list_data.size() )); }catch(Exception e) { e.printStackTrace(); }
好了,到這里問題解決
ps 中間考慮過的方法還有一種,就是獲取當前position,經過判斷需要位移多受啊能到初始位置,就在刷新時偏移多少,但
是經測試,發現一個問題,在
vp_top.setCurrentItem(vp_top.getCurrentItem()+1);這樣偏移一個單位時是沒問題的,但是大於1就會卡頓,這個原因
不是很清楚,可能還是跟view的實例化有關,還需要深入研究