關於ViewPager設置屬性頁setCurrentItem會阻塞主線程ANR總結


 

關於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。問題便得帶了根本的解決。

 

 

無限輪播圖填坑--ViewPager 調用setCurrentItem(int position) 卡死

標簽: Android輪播圖
 

目錄(?)[+]

 

項目需求有無限輪播圖,之前一直用的沒問題,就用之前的放上去了,但是,有個需求是刷新時,把輪播圖位置復位,心想不就是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的實例化有關,還需要深入研究

 


免責聲明!

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



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