現在基本每個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)