热门标签 | 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自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入解析:手把手教你构建决策树算法
    本文详细介绍了机器学习中广泛应用的决策树算法,通过天气数据集的实例演示了ID3和CART算法的手动推导过程。文章长度约2000字,建议阅读时间5分钟。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 自学编程与计算机专业背景者的差异分析
    本文探讨了自学编程者和计算机专业毕业生在技能、知识结构及职业发展上的不同之处,结合实际案例分析两者的优势与劣势。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 深度学习理论解析与理解
    梯度方向指示函数值增加的方向,由各轴方向的偏导数综合而成,其模长表示函数值变化的速率。本文详细探讨了导数、偏导数、梯度等概念,并结合Softmax函数、卷积神经网络(CNN)中的卷积计算、权值共享及池化操作进行了深入分析。 ... [详细]
  • 机器学习中的相似度度量与模型优化
    本文探讨了机器学习中常见的相似度度量方法,包括余弦相似度、欧氏距离和马氏距离,并详细介绍了如何通过选择合适的模型复杂度和正则化来提高模型的泛化能力。此外,文章还涵盖了模型评估的各种方法和指标,以及不同分类器的工作原理和应用场景。 ... [详细]
  • 深入浅出:Google工程师的算法学习指南
    通过Google工程师的专业视角,带你系统掌握算法的核心概念与实践技巧。 ... [详细]
author-avatar
厉害了
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有