在Android中高效的加载大图的方法示例

将大图加载到内存中总是令人痛苦,因为我们经常会在应用的崩溃报告中看到OOM(Out Of Memory)的bug。大家都知道,Android系统的内存有限。我们必须牢记这一点。

stackoverflow上有很多关于大图加载的问题,当你的应用程序遇到OOM的时候,你可以选择直接复制粘贴其中的答案来解决这个问题。因此,你完全可以略过本篇文章,但我想介绍一些加载大图的基础知识及其实际工作的原理。

我只想解释图片解码背后的逻辑。我建议你使用Picasso或Glide来加载图片。没有必要重新发明轮子。

将图片加载到内存中

这很简单。你只需要使用BitmapFactory来解码你的图片。

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage);
imageView.setImageBitmap(bitmap);

看起来一切正常。但是我要告诉你一个问题,让我们看看这张解码过的图片在内存中实际占据的空间大小。

bitmap.getByteCount()方法将返回bitmap的大小。 这张图片在内存中的大小为12262248字节,相当于12.3 MB。是的,你可能会感到困惑。因为这张图片在磁盘上的实际大小约为3.5 MB,而getByteCount()方法返回的值远大于它。原因如下:

存储在磁盘上的图片是被压缩过的(以JPG,PNG或类似的格式存储)。 一旦将图片加载到内存中,它就不再被压缩,并占用尽可能多的图片的所有像素所需的内存空间。

加载大图的步骤

  1. 获取图片的宽和高
  2. 根据图片的宽和高计算缩放比
  3. 使用压缩比将图片加载到内存中。

BitmapFactory.Options

BitmapFactory可以为我们提供图片的元数据。我们可以使用这个类来实现第一步。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

我们将BitmapFactory.Options实例传递给BitmapFactory.decodeSource()方法。 options.inJustDecodeBounds = true 是什么意思?这句代码是指我们不想将图片加载到内存中。我们只想获取图片的相关信息(宽度,高度等),并使用这些信息来计算缩放比例。

我们运行这段代码和并打印图片的信息:

options.outHeight : 1126
options.outWidth : 2000
options.bitmap : null

它只输出了图片的高度和宽度。

Reducing Image Size (In Memory)

现在我们需要计算 inSampleSize 。什么是inSampleSize? inSampleSize是BitmapFactory.Options类的一个属性,用于设置图片的缩放比。

如果我们有一张尺寸为1000x1000的图片,并且在解码之前设置inSampleSize的值为2, 那么解码之后,我们将得到一张尺寸为500x500的图片。 如果我们有一张尺寸为200x400的图片,并且在解码之前设置inSampleSize的值为5, 那么解码之后,我们将得到一张尺寸为40x80的图片。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 3;
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

我们可以直接这样做吗?不能,因为我们不知道图片大小是多少。如果它是小图片,并且我们使其更小,那么我们的用户可以看到的就是一些像素而不是图像。有一些图片需要缩放5倍,另一些图片则需要缩放2倍。我们不能将缩放比设置为一个常数,所以我们必须根据图片的大小来计算它的值。

如何计算inSampleSize的值取决于您。我的意思是,你可以根据你的需要编写inSampleSize的计算方法。在android官方文档中,计算结果是2的幂次方。

options.inSampleSize = calculateInSampleSize(options, 500,500);
options.inJustDecodeBounds = false;
Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

这里我们将 inJustDecodeBounds 的值设为false,并获得了一个bitmap对象。现在,bitmap.getByteCount()方法返回的图片大小是3.1 MB。这是它在内存中的大小。正如我之前说过的,图片存储在磁盘上时会被压缩。当我们将它们加载到内存中时它们会占据更大的内存空间。通过上面这种方法,我们将它在内存中占据的空间大小从12.3 MB减少到了3.1 MB,减少了75%。

Reducing Image Size (In Disk)

我们还可以使用Bitmap的 compress 方法对磁盘上的图片进行压缩。

我们来看看在不改变图片质量的情况下图片被压缩后的大小。 100 表示与原图保持相同的质量。

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] bitmapdata = bos.toByteArray();

通过计算得到图片在磁盘上的大小为1.6 MB。

我们把compress方法中的质量参数改为50,并再次计算图片大小。

bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bos);

通过计算得到图片在磁盘上的大小为24.4 KB。

注意:在改变compress方法中的质量参数的时候,压缩格式应该是.JPEG。设置为PNG格式的时候,修改是无效的。

下面是一张对比效果图:

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

(0)

相关推荐

  • Android 实现加载大图片的方法

    项目简介: 该项目为加载大图片 详细介绍: 对于超大的图片,如果不缩放的话,容易导致内存溢出.而经过处理后,无论多大的图片,都能够在手机屏幕上加载出来,不会导致内存溢出.当然,脸黑的除外 该应用涉及到的知识有: - 1.Bitmap的使用 - 2.Android手机中加载图片的原理 有的时候,我们加载一张不足1M的图片,尽管手机的堆内存有16M,仍然会导致内存溢出,why? 这就更计算机加载图片的原理有关了: 1).手机会解析图片的所有像素信息,把每个像素信息都存入到内存中 2).Android

  • Android 加载大图及多图避免程序出现OOM(OutOfMemory)异常

    Android 加载大图及多图避免程序出现OOM(OutOfMemory)异常 1.高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是用手机摄像头拍出来的,这些图片的分辨率会比我们手机屏幕的分辨率高得多.大家应该知道,我们编写的应用程序都是有一定内存限制的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常.我们可以通过下面的代码看

  • Android高效加载大图、多图解决方案 有效避免程序OOM

    本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/training/displaying-bitmaps/index.html 高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是用手机摄像头拍出来的,这些图片的分辨率会比我们手机屏幕的分辨

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

    一.背景 最近做项目需要用到选择图片上传,类似于微信.微博那样的图片选择器,ContentResolver读取本地图片资源并用RecyclerView+Glide加载图片显示就搞定列表的显示,这个没什么大问题,重点是,点击图片进入大图浏览,比如你相册有几百张图片,也就意味着在ViewPager中需要加载几百个view,况且手机拍出来的图片都是1-2千万左右像素的高清大图(笔者手机2千万像素 也就是拍照出来的照片3888*5152),大小也有5-7个兆,ViewPager滑动不了十几张就oom了,

  • Android开发实现ImageView加载摄像头拍摄的大图功能

    本文实例讲述了Android开发实现ImageView加载摄像头拍摄的大图功能.分享给大家供大家参考,具体如下: 这个方法是从官方demo中摘录的,在此记录学习. 权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera2" android:re

  • Android 加载大图、多图和LruCache缓存详细介绍

    我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是用手机摄像头拍出来的,这些图片的分辨率会比我们手机屏幕的分辨率高得多.大家应该知道,我们编写的应用程序都是有一定内存限制的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常.我们可以通过下面的代码看出每个应用程序最高可用内存是多少 int maxMemory = (int) (Runtime.ge

  • Android实现网络加载图片点击大图后浏览可缩放

    本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下 找了一些demo感觉没有自己想要的效果,于是借鉴一些改造一下并记录下来: 1.主Activity public class PictureViewFra extends Activity { private PicGallery gallery; // private ViewGroup tweetLayout; // 弹层 private boolean mTweetShow = false; // 弹层是否

  • 在Android中高效的加载大图的方法示例

    将大图加载到内存中总是令人痛苦,因为我们经常会在应用的崩溃报告中看到OOM(Out Of Memory)的bug.大家都知道,Android系统的内存有限.我们必须牢记这一点. stackoverflow上有很多关于大图加载的问题,当你的应用程序遇到OOM的时候,你可以选择直接复制粘贴其中的答案来解决这个问题.因此,你完全可以略过本篇文章,但我想介绍一些加载大图的基础知识及其实际工作的原理. 我只想解释图片解码背后的逻辑.我建议你使用Picasso或Glide来加载图片.没有必要重新发明轮子.

  • Android开发中Listview动态加载数据的方法示例

    本文实例讲述了Android开发中Listview动态加载数据的方法.分享给大家供大家参考,具体如下: 最近在研究网络数据加载的问题,比如我有几百,甚至上千条数据,这些数据如果一次性全部加载到arraylist,然后再加载到Listview中.我们必然会去单独开线程来做,这样造成的结果就是会出现等待时间很长,用户体验非常不好.我的想法是动态加载数据,第一次加载十条,然后往下面滑动的时候再追加十条,再往下面滑动的时候再去追加,这样大大减少了用户等待的时间,同时给处理数据留下了时间.网上看到了这样一

  • Android之高效加载大图的方法示例

    加载大图到内存是一件令人头疼的事情.因为大图的原因,我们会在Crash报告中看到OOM(内存不足).Android的内存有限,这一点我们应该心里有数. stackoverflow上有许多相关问题的回答,当你碰到oom时,可以直接跳过本文,粘贴复制答案即可.但是对于其他人来说,我想告诉你们一些加载大图的知识和原理. 加载Bitmap到内存 so easy.你所需要做的就是使用BitmapFactory解码你的图片. Bitmap bitmap = BitmapFactory.decodeResou

  • 详细讲解Android中使用LoaderManager加载数据的方法

    Android的设计之中,任何耗时的操作都不能放在UI主线程之中.所以类似于网络操作等等耗时的操作都需要使用异步的实现.而在ContentProvider之中,也有可能存在耗时的操作(当查询的数据量很大的时候),这个时候我们也需要使用异步的调用来完成数据的查询. 当使用异步的query的时候,我们就需要使用LoaderManager了.使用LoaderManager就可以在不阻塞UI主线程的情况下完成数据的加载. (1)获取loaderManger:activity.getLoaderManag

  • Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而Ima

  • Android中替换WebView加载网页失败时的页面

    我们用webView去请求一个网页链接的时候,如果请求网页失败或无网络的情况下,它会返回给我们这样一个页面,如下图所示: 上面这个页面就是系统自带的页面,你觉得是不是很丑?反正小编本人觉得非常丑,很难看,于是乎小编就在想能不能自定义一个页面,当数据请求失败时让系统来加载我们自定义好的页面?上网查了很多资料,都没有关于这个问题的解决方法(反正我是没有找到),经过小编的不断琢磨,今天终于实现了这个功能.以下就是本人自定义实现的数据加载失败时的页面: 这样看起来是不是觉得很高大尚.这和我们真正拿到数据

  • Android中利用动态加载实现手机淘宝的节日特效

    相信去年圣诞节打开过手机淘宝的童鞋都会对当时的特效记忆犹新吧:全屏飘雪,旁边还有个小雪人来控制八音盒背景音乐的播放,让人有种身临其境的感觉,甚至忍不住想狠狠购物了呢(误),大概就是下面这个样子滴: 嗯,确实很炫,那么我们一步步去分析是如何实现的: 一.实现下雪的 View 首先,最上面一层的全屏雪花极有可能是一个顶层的View,而这个View是通过动态加载去控制显示的(不更新淘宝也能看到这个效果).那么我们先得实现雪花效果的 View,人生苦短,拿来就用.打开 gank.io,搜索"雪花&quo

  • 如何在iOS中高效的加载图片详解

    目录 前言 图片的渲染流程 DataBuffer SD源码分析 ImageBuffer 占用内存大小 Xcode测试 如何减少图像占用内存 向下采样 SD源码分析解码过程 选择正确的图片渲染格式 渲染格式 如何正确的选择渲染格式 减少后备存储器的使用 减少或者不使用 draw(rect:) 方法 如何在列表中加载图片 线程爆炸 总结 前言 在iOS开发中,图片(UIImage)是我们在开发中,占用手机内存比较大的对象,如果在运行过程中,内存占用过大,对电池寿命会造成影响,如果超过了内存占用的最大

  • PHP中的自动加载操作实现方法详解

    本文实例讲述了PHP中的自动加载操作实现方法.分享给大家供大家参考,具体如下: what is 自动加载? 或许你已经对自动加载有所了解.简单描述一下:自动加载就是我们在new一个class的时候,不需要手动去写require来导入这个class.php文件,程序自动帮我们加载导入进来.这是php5.1.2(好像是)版本新加入一个功能,他解放了程序员的双手,不需要手动写那么多的require,变得有那么点智能的感觉. 自动加载可以说是现代PHP框架的根基,任何牛逼的框架或者架构都会用到它,它发明

  • Android实现ListView异步加载图片的方法

    本文实例讲述了Android实现ListView异步加载图片的方法.分享给大家供大家参考.具体如下: ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,不用让用户等待下去,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReferen

随机推荐