Loading

ViewPager做图片浏览器,加载大量图片OOM的问题修正

  1 /**
  2  * @author CHQ
  3  * @version 1.0
  4  * @date 创建时间: 2016/7/26 17:18
  5  * @parameter
  6  * @return
  7  * 图片查看器
  8  * //可以查看网络图片
  9  * //可以查看本地图片
 10  */
 11 public class PhotoScan extends Activity {
 12     private PhotoViewPager mViewPager;
 13     private List<View> mViews;
 14     private List<String> mPics;
 15     private int index;
 16 
 17     private ImageView mImageView; //当前图片
 18     private PhotoViewAttacher mAttacher; //图片放大缩小查看
 19 
 20     private TextView tv_hint01;
 21     private TextView tv_hint02;
 22     private int imageType = 0;  //判断图片浏览器查看的图片类型:0.网络图片  1.本地图片
 23     private LruCache<String,Bitmap> mLruCache;
 24     private int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);
 25 
 26     @Override
 27     protected void onCreate(Bundle savedInstanceState) {
 28         super.onCreate(savedInstanceState);
 29         setContentView(R.layout.activity_picture_view);
 30         init();
 31         setEvent();
 32     }
 33 
 34     private void init() {
 35         MyApplication.getInstance().addActivity("PhotoScan",PhotoScan.this);
 36         index = getIntent().getIntExtra("index",0);
 37         imageType = getIntent().getIntExtra("imageType",0);
 38         mViewPager = (PhotoViewPager) findViewById(R.id.viewPager);
 39         mLruCache = new LruCache<>(maxMemory/8);
 40         tv_hint01 = (TextView) findViewById(R.id.tv_hint01);
 41         tv_hint02 = (TextView) findViewById(R.id.tv_hint02);
 42 
 43         mPics = getIntent().getStringArrayListExtra("pics");
 44         tv_hint02.setText(" /"+mPics.size());
 45         mViews = new ArrayList<>();
 46         LayoutInflater inflater = LayoutInflater.from(this);
 47         for(int i = 0 ; i< mPics.size() ; i++){
 48             View view = inflater.inflate(R.layout.item_picture_view,null);
 49             mViews.add(view);
 50         }
 51 
 52         MyAdapter adapter = new MyAdapter(mViews,mPics,this);
 53         mViewPager.setAdapter(adapter);
 54         mViewPager.setCurrentItem(index);
 55         index += 1;   //设置当前图片指示器
 56         tv_hint01.setText(""+index);
 57     }
 58 
 59     private void setEvent() {
 60         mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
 61             @Override
 62             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 63 
 64             }
 65             @Override
 66             public void onPageSelected(int position) {
 67                 index = position+1;  //设置当前图片指示器
 68                 tv_hint01.setText(""+index);
 69             }
 70             @Override
 71             public void onPageScrollStateChanged(int state) {
 72 
 73             }
 74         });
 75     }
 76 
 77     @Override
 78     public boolean onKeyDown(int keyCode, KeyEvent event) {
 79         if(keyCode == KeyEvent.KEYCODE_BACK){
 80             MyApplication.getInstance().deleteActivity("PhotoScan",PhotoScan.this);
 81         }
 82         return super.onKeyDown(keyCode, event);
 83     }
 84 
 85     private class MyAdapter extends PagerAdapter{
 86         List<View> mViews;
 87         List<String> mPics;
 88         Context context;
 89         public MyAdapter(List<View> mViews,List<String> mPics,Context context){
 90             this.mViews = mViews;
 91             this.mPics = mPics;
 92             this.context = context;
 93         }
 94         //viewpager中的组件数量
 95         @Override
 96         public int getCount() {
 97             return mViews.size();
 98         }
 99 
100         //滑动切换的时候销毁当前的组件
101         @Override
102         public void destroyItem(ViewGroup container, int position, Object object) {
103             ((ViewPager)container).removeView(mViews.get(position));
104         }
105 
106         //每次滑动的时候,生成组件
107         @Override
108         public Object instantiateItem(ViewGroup container, int position) {
109             View view = mViews.get(position);
110             mImageView = ((ImageView) view.findViewById(R.id.iv));
111             String picurl = mPics.get(position);
112             setPic(picurl,view);
113             ((ViewPager)container).removeView(mViews.get(position));
114             ((ViewPager)container).addView(mViews.get(position));
115             return mViews.get(position);
116         }
117 
118         @Override
119         public boolean isViewFromObject(View view, Object object) {
120             return view == object;
121         }
122 
123         @Override
124         public int getItemPosition(Object object) {
125             return super.getItemPosition(object);
126         }
127     }
128 
129     /**
130      * 加载网络图片
131      */
132     private void setPic(String picurl, final View parentView){
133         if(!picurl.contains("http://") && imageType == 0) {
134             picurl = MyConfig.picFirst+picurl;
135         }
136         if(imageType == 1){  //"/mnt/sdcard/mImageView.png"
137             picurl = ImageDownloader.Scheme.FILE.wrap(picurl);
138         }
139         Log.i("main",picurl);
140         //加载自定义配置的一个图片的,网络加载监听,等待加载图片完成再初始化缩小放大
141         ImageLoader.getInstance().displayImage(picurl, mImageView, MyApplication.OptionsNoCache, new SimpleImageLoadingListener() {
142             @Override
143             public void onLoadingStarted(String imageUri, View view) {
144                 super.onLoadingStarted(imageUri, view);
145                 Utility.setLoadingProgressbar(null,parentView,true);
146             }
147 
148             @Override
149             public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
150                 super.onLoadingComplete(imageUri, view, loadedImage);
151                 Utility.setLoadingProgressbar(null,parentView,false);
152                 mAttacher = new PhotoViewAttacher(mImageView);
153                 mAttacher.update();
154             }
155         }, new ImageLoadingProgressListener() {
156             @Override
157             public void onProgressUpdate(String s, View view, int i, int i1) {
158                 Log.i("main","i="+i+",il="+i1);
159             }
160         });
161 
162     }
163 }
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:orientation="vertical"
 7     >
 8     <include
 9         layout="@layout/ll_progessbar1"
10         />
11     <ImageView
12         android:id="@+id/iv"
13         android:layout_width="match_parent"
14         android:layout_height="match_parent"
15         android:scaleType="centerInside"
16         >
17     </ImageView>
18 </LinearLayout>

mViews<View>存放在(包含)ImageView的引用,随着imageView设置Bitmap的增加,大概30张大图之后就基本OOM了,这时要做优化修改:

1、修改mViews的大小,默认只有4个

1 for(int i = 0 ; i< 4 ; i++){
2             View view = inflater.inflate(R.layout.item_picture_view,null);
3             mViews.add(view);
4         }

2、修改容器里面关于mViews的使用


private class MyAdapter extends PagerAdapter{
List<View> mViews;
List<String> mPics;
Context context;
public MyAdapter(List<View> mViews,List<String> mPics,Context context){
this.mViews = mViews;
this.mPics = mPics;
this.context = context;
}
//viewpager中的组件数量
@Override
public int getCount() {
return mPics.size();
}

//滑动切换的时候销毁当前的组件
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
int i = position%4;
Log.i("main","正在销毁第几页:"+position+",正在销毁对应mViews的第几个数据源:"+i);
((ViewPager)container).removeView(mViews.get(i));
}

//每次滑动的时候,生成组件
@Override
public Object instantiateItem(ViewGroup container, int position) {
int i = position%4;
View view = mViews.get(i);
mImageView = ((ImageView) view.findViewById(R.id.iv));
String picurl = mPics.get(position);
setPic(picurl,view);
Log.i("main","正在生成第几页:"+position+",正在调用mViews的第几个数据源:"+i);
((ViewPager)container).addView(mViews.get(i));
return mViews.get(i);
}

@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}

@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
}

/**
* 加载网络图片
*/
private void setPic(String picurl, final View parentView){
if(!picurl.contains("http://") && imageType == 0) {
picurl = MyConfig.picFirst+picurl;
}
if(imageType == 1){ //"/mnt/sdcard/mImageView.png"
picurl = ImageDownloader.Scheme.FILE.wrap(picurl);
}
Log.i("main",picurl);
//加载自定义配置的一个图片的,网络加载监听,等待加载图片完成再初始化缩小放大
ImageLoader.getInstance().displayImage(picurl, mImageView, MyApplication.OptionsWithCache, new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
super.onLoadingStarted(imageUri, view);
Utility.setLoadingProgressbar(null,parentView,true);
}

@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
Utility.setLoadingProgressbar(null,parentView,false);
mAttacher = new PhotoViewAttacher(mImageView);
mAttacher.update();
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String s, View view, int i, int i1) {
Log.i("main","i="+i+",il="+i1);
}
});

}
 

也就是说,整个方案中最多只保存3个ImageView,建立4个数据源的mViews,那时因为ViewPager在滑动的时候:

打开第一页时:

第2页、第3页:

第4页、第5页:

第5页-》第4页:

这里可以看到,从第2页滑动向第3页时,是先销毁第1页,再构造第3页,也就是先destoryItem再InstantiateItem,而销毁和构造ViewPager视图的都是用到同一个mView.get(i)(如从第2-》3页,销毁和构造都是0;从第4-》5页,销毁和构造都是2),这里是无问题的;

 

但是,如果从第5页滑到回来第4页就出问题了,这里是先构造第4页的前前一页,也就是第2页,销毁的时候,正在被当前视图使用,这里就会出错了。所有改用包含4个子项的mViews

 

最后上一个修改之后的log,页数变化如:1-2-3-4-5-6-5-4

 

posted @ 2016-07-28 16:03  集君  阅读(2381)  评论(1编辑  收藏  举报