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

时间: 2024-12-26 14:47:22

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

客户端实现图片滑动加载,资讯详情页面

展示方案:客户端请求资讯详情数据接口获取 富文本数据 客户端使用WebView展示. 当文章详情篇幅长.包含图片多一次性加载全部图片会造成客户端短暂的卡顿 影响用户体验 所以考虑计划做图片滑动加载 默认使用统一的占位图. 本以为使用一个前端jquery插件(jquery.lazyload.js)就可以解决,应用这个插件后,出现问题所有图片还是一次性加载完成,不是滑动加载,分析发现是因为客户端在实现webview的时候要定义页面中的标题.评论.相关文章等不能够给设置webview的高度为固定手机屏

【vue】vue-cli3构建项目中实现图片懒加载

前两天正好写了文章如何用实现图片懒加载[性能优化]JS实现图片懒加载,今天在使用vue构建项目的时候就遇到了要做图片懒加载的优化需要,本想把前两天的代码直接copy过来的,后来想查查看有没有更简便的方法,果不其然,vue中直接有插件可以使用,看了下实现时候的效果,实现原理都和原生js是一样的,vue果然真香! 接下来我们来讲vue-lazyload插件的使用: 1.安装插件 cnpm i vue-lazyload -S 2.入口文件main.js中配置: import Vue from 'vue

Android 大图片加载 避免OOM

文章来自郭大神:======= 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9316683 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/training/displaying-bitmaps/index.html 高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.

图片路径加载失败,火狐浏览器默认显示断裂图片

在谷歌.IE浏览器中,如果图片路径加载失败,会显示一个默认的断裂图片,像这个样子 而在火狐浏览器中,则图片不会有任何占位,这样就会导致布局上的混乱,用户体验也不好,如何让火狐浏览器显示出断裂图片效果呢? 只需在样式文件css中加入这行代码就可以啦 @-moz-document url-prefix(http), url-prefix(file) { img:-moz-broken { -moz-force-broken-image-icon: 1; width:24px; height:24px

2017.8.5 浏览器中图片的加载

浏览器加载一个html页面: 解析html===>构建DOM树 -----遇到img标签加载图片 加载样式===>解析样式       ===>构建样式规则树 -----遇到背景图片链接不加载 加载js     ===>执行js 把DOM树和样式规则树匹配构建渲染树 ----加载渲染树上的背景图片 计算元素位置进行布局 绘制  ----渲染图片

爬虫之 图片懒加载, selenium , phantomJs, 谷歌无头浏览器

一.图片懒加载 什么是图片懒加载? 案例分析:抓取站长素材http://sc.chinaz.com/中的图片数据 #!/usr/bin/env python # -*- coding:utf-8 -*- import requests from lxml import etree if __name__ == "__main__": url = 'http://sc.chinaz.com/tupian/gudianmeinvtupian.html' headers = { 'User-

封装的图片预加载,数据加载到浏览器底部加载数据

html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="jquery-1.8.3.min.js" type="text/javascript"></script> <style> *{ padding:0; margin:0

Android图片异步加载之Android-Universal-Image-Loader

将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就顺便整理记录下来,作为这一个多月来博客的重新开火做饭吧.从今天起我会陆续恢复博客的更新,也希望大家继续支持. 今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异

Android图片异步加载之Android-Universal-Image-Loader(转)

今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决方案.做Android的同学都知道,Android加载大量图片时,由于系统分配给图片加载的内存大小有限,所以,如果加载图片量非常大的话容易报OOM异常,关于这个异常已经有不少解决方案了,我就不赘述.下面就简要介绍下这个开源项目的主要功能和使用: 一.功能概要 多线程图片加载: 灵活更改ImageLo