热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

详解Android_性能优化之ViewPager加载成百上千高清大图oom解决方案

这篇文章主要介绍了详解Android_性能优化之ViewPager加载成百上千高清大图oom解决方案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

一、背景

最近做项目需要用到选择图片上传,类似于微信、微博那样的图片选择器,ContentResolver读取本地图片资源并用RecyclerView+Glide加载图片显示就搞定列表的显示,这个没什么大问题,重点是,点击图片进入大图浏览,比如你相册有几百张图片,也就意味着在ViewPager中需要加载几百个view,况且手机拍出来的图片都是1-2千万左右像素的高清大图(笔者手机2千万像素 也就是拍照出来的照片3888*5152),大小也有5-7个兆,ViewPager滑动不了十几张就oom了,即是对图片做了压缩处理,把图片分辨率降低至1366*960,大小压缩至150k以下,并且在ViewPager的destroyItem方法做了bitmap资源的回收,虽然效果好了点,这也抵挡不了oom的降临(网上查找的方案都是压缩、使用第三方控件、回收,其实这都没用,可能他们没有真正体验过ViewPager加载几百上千张大图的感受),浏览到了第50-70张的时候就oom了 内存一直暴涨,根本回收不了的,不信你们试试,压缩和回收根本不能根治问题,那么怎么解决呢?研究了微信和微博,他们怎么也不会oom,最后我想到了一种解决方案。

二、方案实施

1、以往的普通做法

部分代码:

List mViews = new ArrayList<>(); 
     
    int size = mDatas.size(); 
    for (int i = 0; i 
class MyAdapter extends PagerAdapter { 
 
    @Override 
    public int getCount() { 
      return mDatas.size(); 
    } 
 
    @Override 
    public boolean isViewFromObject(View view, Object object) { 
      return view == object; 
    } 
 
    @Override 
    public Object instantiateItem(ViewGroup container, final int position) { 
 
      ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( 
          ViewPager.LayoutParams.MATCH_PARENT,ViewPager.LayoutParams.MATCH_PARENT); 
      final SubsamplingScaleImageView imageView = mViews.get(position); 
      imageView.setLayoutParams(params); 
 
      final String url = mDatas.get(position); 
      String cacheExists = cacheExists(url); 
      if(TextUtils.isEmpty(cacheExists)) {//没缓存 需要压缩(压缩耗时 异步) 
        new AsyncTask() { 
          @Override 
          protected String doInBackground(Void... voids) { 
            String cacheNoExistsPath = getCacheNoExistsPath(url); 
            BitmapCompressUtils.compressBitmap(url, cacheNoExistsPath); 
            File file = new File(cacheNoExistsPath); 
            if (file.exists()) {//存在表示成功 
              return cacheNoExistsPath; 
            } else { 
              return url; 
            } 
          } 
 
          @Override 
          protected void onPostExecute(String s) { 
            imageView.setImage(ImageSource.uri(s)); 
          } 
 
        }.execute(); 
 
 
      } else {//有缓存 直接显示 
        imageView.setImage(ImageSource.uri(cacheExists)); 
      } 
 
      container.addView(imageView); 
      return imageView; 
 
    } 
 
    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
 
      SubsamplingScaleImageView imageView = mViews.get(position); 
      if(imageView != null) { 
        imageView.recycle(); 
      } 
 
      container.removeView(imageView); 
 
    } 
  } 

/** 
   * 判断当前图片url对应的压缩过的缓存是否存在 ""表示不存在 
   * 
   * @param url 图片路径 
   * @return 
   */ 
  private String cacheExists(String url) { 
    try { 
      File fileDir = new File(mCacheRootPath); 
      if(!fileDir.exists()) { 
        fileDir.mkdirs(); 
      } 
 
      File file = new File(mCacheRootPath,new StringBuffer().append(MD5EncryptorUtils.md5Encryption(url)).toString()); 
      if(file.exists()) { 
        return file.getAbsolutePath(); 
      } 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
 
    return ""; 
  } 
 
  public String getCacheNoExistsPath(String url) { 
    File fileDir = new File(mCacheRootPath); 
    if(!fileDir.exists()) { 
      fileDir.mkdirs(); 
    } 
 
 
    return new StringBuffer().append(mCacheRootPath) 
        .append(MD5EncryptorUtils.md5Encryption(url)).toString(); 
  } 

可以看到,这里笔者通过自己的压缩算法(上一篇文章Android_NDK图片压缩之Libjpeg库使用 )做了图片压缩,并缓存,细心的朋友应该有发现mViews集合添加的view个数是mDatas的size大小个数,这样就会导致一个问题ViewPager一直向下滑动的时候,内存一直是增加的,即是做了资源回收,也是不能解决问题(况且笔者这里展示图片的控件是SubsamplingScaleImageView 很不错的大图局部加载控件 能有效防止oom),大家可以试试,大量图片的时候还是会oom,这得归根于viewpager加载的图片数量问题。

2、解决方案:

图片压缩也做了,资源回收也做了,但是ViewPager加载越来越多图片的时候就会oom 你避免不了,不信你试试;

这里就要用到ViewPager的view的重用机制(自己理解的),也就是mViews我们固定给定个数量,如4,这样ViewPager的i实际所需要的item也就只有4个。

修改后的部分代码:

for (int i = 0; i <4; i++) { 
      SubsamplingScaleImageView view = new SubsamplingScaleImageView(this); 
      mViews.add(view); 
    } 
 
    mBinding.viewpager.setAdapter(new MyAdapter()); 
class MyAdapter extends PagerAdapter { 
 
    @Override 
    public int getCount() { 
      return mDatas.size(); 
    } 
 
    @Override 
    public boolean isViewFromObject(View view, Object object) { 
      return view == object; 
    } 
 
    @Override 
    public Object instantiateItem(ViewGroup container, final int position) { 
 
      ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( 
          ViewPager.LayoutParams.MATCH_PARENT,ViewPager.LayoutParams.MATCH_PARENT); 
 
      int i = position % 4; 
      final SubsamplingScaleImageView imageView = mViews.get(i); 
      imageView.setLayoutParams(params); 
 
      final String url = mDatas.get(position); 
      String cacheExists = cacheExists(url); 
      if(TextUtils.isEmpty(cacheExists)) {//没缓存 需要压缩(压缩耗时 异步) 
        new AsyncTask() { 
          @Override 
          protected String doInBackground(Void... voids) { 
            String cacheNoExistsPath = getCacheNoExistsPath(url); 
            BitmapCompressUtils.compressBitmap(url, cacheNoExistsPath); 
            File file = new File(cacheNoExistsPath); 
            if (file.exists()) {//存在表示成功 
              return cacheNoExistsPath; 
            } else { 
              return url; 
            } 
          } 
 
          @Override 
          protected void onPostExecute(String s) { 
            imageView.setImage(ImageSource.uri(s)); 
          } 
 
        }.execute(); 
 
 
      } else {//有缓存 直接显示 
        imageView.setImage(ImageSource.uri(cacheExists)); 
      } 
 
      container.addView(imageView); 
      return imageView; 
 
    } 
 
    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
      int i = position % 4; 
      SubsamplingScaleImageView imageView = mViews.get(i); 
      if(imageView != null) { 
        imageView.recycle(); 
      } 
 
      container.removeView(imageView); 
 
    } 

很简单的修改 就能有效防止oom  利用position%4拿到第几个控件从mViews取值,保证了viewpager加载的mViews存储的图片为4个

看一直向下滑动的内存走势图

内存基本维持稳定

三、demo演示

因为要读取相册就没再模拟器运行录制gif ,直接截图


 

demo下载:demo

四、总结

这个只是简单的演示,实际项目中的相册比这个复杂多了,简单说就是要压缩,要回收,View重用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
author-avatar
chen-yu2502881617
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有