Android 導航(介紹)頁面ViewPager內存溢出解決方法


現在基本每個Android App都會標配一個啟動介紹的頁面,或做產品介紹,或做app功能展示,既然起導航界面,基本思路就是用ViewPager實現。(圖片引自UI中國一設計師的設計圖片) 

正好這幾天在做這個導航界面,我的測試手機是魅族MX3,做完之后測試還行,沒有明顯卡頓的現象,但是當我把debug的apk裝到米3和魅藍上時,程序運行到這個導航界面會馬上crash掉,偶爾沒有crash也會出現明顯的卡頓現象,體驗效果非常差。 
打開Android Studio的內存管理器查看運行時分配內存,當時我就蒙逼了,180+M左右,就這個導航界面用了180M,還做什么安卓。。。 
改了很多地方,效果依舊不明顯,查閱資料有說另外寫一個Adapter繼承自PagerAdapter,方法如下:

 1 class GuideAdapter extends PagerAdapter{
 2         private List<View> views;
 3         private final LinkedList<View> recyleBin=new LinkedList<>();
 4         public GuideAdapter(List<View>views){
 5             this.views=views;
 6         }
 7         @Override
 8         public int getCount() {
 9             return views.size();
10         }   
11         @Override
12         public boolean isViewFromObject(View view, Object object) {
13             return view==object;
14         }   
15         @Override
16         public void destroyItem(ViewGroup container, int position, Object object) {
17             container.removeView(views.get(position));
18         }   
19         @Override
20         public int getItemPosition(Object object) {
21             return super.getItemPosition(object);
22         }   
23         @Override
24         public Object instantiateItem(ViewGroup container, int position) {
25             //在此設置背景圖片,提高加載速度,解決OOM問題
26             View view;
27             int count=getCount();
28             if(!recyleBin.isEmpty()) {
29                 view=recyleBin.pop();
30             }else {
31                 view=views.get(position);
32                 ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
33                         ViewGroup.LayoutParams.MATCH_PARENT,
34                         ViewGroup.LayoutParams.MATCH_PARENT);
35                 view.setBackgroundResource(images[position % count]);
36                 view.setLayoutParams(params);
37             }
38             container.addView(view,0);
39             return views.get(position);
40         }
41 }

 

初始化的時候讓viewpager的adapter為上面的自定義的adapter即可,基本代碼如下:

 1 private ViewPager mViewPager;
 2     private GuideAdapter mGuideAdapter;
 3     private int[] images;//顯示介紹的圖片的id值
 4     private ArrayList<View>views;
 5     private ImageView[] indicator=null;//下面的導航指示器,此處不做過多介紹,可忽略
 6 
 7     ...
 8     ...
 9     //控件初始化業務
10     mViewPager=(ViewPager)findViewById(R.id.viewpager);
11     views=new ArrayList<>();
12     //此處放入五張介紹的圖片的id值
13     images=new int[]{R.drawable.bg_1,R.drawable.bg_2,R.drawable.bg_3,R.drawable.bg_4,R.drawable.bg_5}
14     //adapter實例化
15     mGuideAdapter=new GuideAdapter(views);
16     //循環加入圖片的業務
17     for(int i=0;i<images.length;i++){
18         ImageView mImageView=new ImageView(this);
19     //下面這一步會導致OOM,所以添加backgroundResource的步驟在自定義的adapter的
20     //instantiateItem方法里面實現,此處已注釋
21     //mImageView.setBackgroundResource(images[i]);
22     views.add(mImageView);//添加入動態數組里面,此處的ImageView里面均為沒有背景的imageview
23     //for循環內還有指示器的添加,因不在討論問題的重點內,忽略業務代碼
24     }
25     //為mViewPager綁定適配器
26     mViewPager.setAdapter(mGuideAdapter);
27     mViewPager.setCurrentItem(0);
28     mViewPager.setOffscreenPageLimit(1);
29     mViewPager.setOnPageChangeListener(this);
30     ...
31     ...

基本的思路就是讓加載viewpager過多的沒有顯示的圖片在自定義的Adapter的destroyItem里面銷毀釋放內存,防止造成OOM或者內存溢出crash的問題,這種方法每次加載viewpager的時候只會加載當前一頁和前后兩頁共三頁,所以內存占用不會很高。

但是,但是,問題來了。。。重新編寫之后測試發現:te me還是占用160M+內存,當時我就傻了。。。怎么不見效果呢。。。於是好長時間都在查資料,找問題,debug。。。 
然而,半天過去了。。。 
我還是沒找到問題到底出在哪里。。。 
后來,導師和我說看一下你的圖片多少大,我說100k的樣子,然后他看了一下,說讓我把所有圖片拖到PS里面轉成PNG再導出來(之前一直都是JPG)。於是照做了,順便看了一眼新導出的圖片大小,看了一下都比JPG的要大,於是半信半疑的替換資源,重新編譯運行后。終於驚喜的發現內存占用降到40-60M之間了。。。原來是圖片格式的問題,欸,搞了半天頭都大了,原來是這么簡單的問題。。。 
這也橫向提示我們以后Android編程里面的資源最好不要用JPG格式的,下載類的圖片資源也是,因為32位的PNG顏色過渡平滑且支持透明,JPG是像素化壓縮過的圖片,質量已經下降了,PNG的壓縮算法解壓快很多,JPG的話可以有很高的壓縮比(當然會有損失),所以綜合考慮還是用PNG比較好(特殊需求除外)。

在此也感謝我的導師,在我開發當中教我好多,第一次寫博客,即當作自己的記事本,日后還能看看,也希望能解決大家相似的問題,第一次寫,一定會有表達不到位,表述不清楚的地方,希望留下你的評論和建議,我也可以改正,提高自己。

(本博客屬於本人原創,本人CSDN文章原創地址:http://blog.csdn.net/wiz_chen/article/details/45119783)


免責聲明!

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



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