转自:http://www.cnblogs.com/plokmju/p/android_LoadBigImage.html
前言
在使用ImageView显示图片的时候,直接加载一个图片资源到内存中,经常会出现内存溢出的错误,这是因为有些图片的分辨率比较高,把它直接加载到内存中之后,会导致堆内存溢出的问题。这篇博客就来讲解一下Android的堆内存以及如何在Android应用中加载一个高分辨率的图片。关于ImageView不熟悉的朋友,可以看看之前的博客:Android--ImageView。
本篇博客的主要内容:
首先来还原一下堆内存溢出的错误。首先在SD卡上放一张照片,分辨率为(3776 X 2520),大小为3.88MB,是我自己用相机拍的一张照片。应用的布局很简单,一个Button一个ImageView,然后按照常规的方式,使用BitmapFactory加载一张照片并使用一个ImageView展示。
代码如下:
1 btn_loadimage.setOnClickListener(new View.OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 Bitmap bitmap=BitmapFactory.decodeFile("/sdcard/a.jpg"); 6 iv_bigimage.setImageBitmap(bitmap); 7 } 8 }
当点击按钮后,程序会报错,查看日志为:
先来分析一下这个错误,首先dalvikvm(Android虚拟机)发现需要的内存38MB大于应用的堆内存24MB,这个时候尝试使用软加载的方式加载数据,我们知道当内存不足的时候dalvikvm会自动进行GC(Garbage Collection),大概清理了55k的空间出来,耗时203毫秒,但是内存还是不够,所以最后发生堆内存溢出的错误。
Android系统主要用于低能耗的移动设备,所以对内存的管理有很多限制,一个应用程序,Android系统缺省会为其分配最大16MB(某些机型是24MB)的空间作为堆内存空间,我这里使用的模拟器调试的,这个模拟器被设定为24MB,可以在Android Virtual Device Manager中查看到。
而这里的图片明明只有3.88MB,远远小于Android为应用分配的堆内存,而加载到内存中,为什么需要消耗大约38MB的内存呢?
我们都知道,图片是由一个一个点分布组成的(分辨率),通常加载这类数据都会在内存中创建一个二维数组,数组中的每一项代表一个点,而这个图片的分辨率是3776 * 2520,每一点又是由ARGB色组成,每个色素占4个Byte,所以这张图片加载到内存中需要消耗的内存为:
3776 * 2520 * 4byte = 38062080byte
大约需要38MB的内存才能正确加载这张图片,这就是上面错误描述需要38MB的内存空间,大小略有出入,因为图片还有一些Exif信息需要存储,会比仅靠分辨率计算要大一些。
有时候我们确实会需要加载一些大分辨率的图片,但是对于移动设备而言,哪怕加载能成功那么大的内存也是一种浪费(屏幕分辨率限制),所以就需要想办法把图片按照一定比率压缩,使分辨率降低,以至于又不需要耗费很大的堆内存空间,又可以最大的利用设备屏幕的分辨率来显示图片。这里就用到一个BitmapFactory.Options对象,下面来介绍它。
BitmapFactory.Options为BitmapFactory的一个内部类,它主要用于设定与存储BitmapFactory加载图片的一些信息。下面是Options中需要用到的属性:
- inJustDecodeBounds:如果设置为true,将不把图片的像素数组加载到内存中,仅加载一些额外的数据到Options中。
- outHeight:图片的高度。
- outWidth:图片的宽度。
- inSampleSize:如果设置,图片将依据此采样率进行加载,不能设置为小于1的数。例如设置为4,分辨率宽和高将为原来的1/4,这个时候整体所占内存将是原来的1/16。
下面通过一个简单的Demo来演示上面提到的内容,代码中注释比较清晰,这里就不再累述了。
1 package cn.bgxt.loadbigimg; 2 3 import android.os.Bundle; 4 import android.os.Environment; 5 import android.app.Activity; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.graphics.BitmapFactory.Options; 9 import android.view.Menu; 10 import android.view.View; 11 import android.view.WindowManager; 12 import android.widget.Button; 13 import android.widget.ImageView; 14 15 public class MainActivity extends Activity { 16 private Button btn_loadimage; 17 private ImageView iv_bigimage; 18 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.activity_main); 23 24 btn_loadimage = (Button) findViewById(R.id.btn_loadimage); 25 iv_bigimage = (ImageView) findViewById(R.id.iv_bigimage); 26 27 btn_loadimage.setOnClickListener(new View.OnClickListener() { 28 29 @Override 30 public void onClick(View v) { 31 // Bitmap bitmap=BitmapFactory.decodeFile("/sdcard/a.jpg"); 32 // iv_bigimage.setImageBitmap(bitmap); 33 34 BitmapFactory.Options opts = new Options(); 35 // 不读取像素数组到内存中,仅读取图片的信息 36 opts.inJustDecodeBounds = true; 37 BitmapFactory.decodeFile("/sdcard/a.jpg", opts); 38 // 从Options中获取图片的分辨率 39 int imageHeight = opts.outHeight; 40 int imageWidth = opts.outWidth; 41 42 // 获取Android屏幕的服务 43 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); 44 // 获取屏幕的分辨率,getHeight()、getWidth已经被废弃掉了 45 // 应该使用getSize(),但是这里为了向下兼容所以依然使用它们 46 int windowHeight = wm.getDefaultDisplay().getHeight(); 47 int windowWidth = wm.getDefaultDisplay().getWidth(); 48 49 // 计算采样率 50 int scaleX = imageWidth / windowWidth; 51 int scaleY = imageHeight / windowHeight; 52 int scale = 1; 53 // 采样率依照最大的方向为准 54 if (scaleX > scaleY && scaleY >= 1) { 55 scale = scaleX; 56 } 57 if (scaleX < scaleY && scaleX >= 1) { 58 scale = scaleY; 59 } 60 61 // false表示读取图片像素数组到内存中,依照设定的采样率 62 opts.inJustDecodeBounds = false; 63 // 采样率 64 opts.inSampleSize = scale; 65 Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/a.jpg", opts); 66 iv_bigimage.setImageBitmap(bitmap); 67 68 } 69 }); 70 } 71 }
效果展示:
总结
本篇博客到这里就讲解了如何加载一个大分辨率的图片到内存中并使用它。不过一般好一点的图片处理软件,都会有图片放大功能,如果仅做此处理,单纯的把处理后的图片放大,会影响显示效果,图片还原度不高。一般会重新获取放大区域的图片的分辨率像素数组,然后重新处理加载到内存中进行显示。
相关推荐
本篇将深入探讨Android图片加载框架的API封装,重点关注Fresco、Glide和Picasso这三大主流库,并介绍如何实现大图预览功能,确保即使在处理大型或轮播图片时,内存占用也能保持在较低水平。 首先,Fresco是一个强大...
由于Android设备的多样性,处理不同分辨率、大小的图片并确保用户体验流畅,需要高效的图片加载库。在本案例中,我们将探讨"Android-Android图片加载库的封装",这通常涉及到对现有开源图片加载库如Glide、Picasso或...
当用户尝试加载一张分辨率高或者尺寸大的图片时,如果不进行任何处理,可能会导致应用崩溃,因为Android系统会尝试一次性加载整张图片到内存中,超出设备的内存限制。长图则更为复杂,由于其横向或纵向的像素数量...
在Android应用开发中,图片加载与管理是一项关键任务,尤其在处理大量图片或者高分辨率图片时,如何高效、节省内存地显示图片至关重要。这就是Fresco库的价值所在。Fresco,由Facebook开发并开源,是一个专门为...
- 在`Gallery`的`OnItemSelectedListener`中启动`AsyncTask`,当用户滚动到新的图片时,取消正在加载的任务并重新加载新选中的图片。 3. **内存管理**: - 使用`LruCache`或`WeakReference`管理缓存图片,防止...
6. **代码整合** - 尽管Android Kitchen通常作为独立工具使用,但它也可以集成到构建流程中,如Gradle或Android Studio的插件,使得资源优化成为构建过程的一部分。 7. **提高用户体验** - 通过提供适配不同设备的...
在Android开发中,图片加载和展示是至关重要的一个环节,特别是在设计用户界面时。SVG(Scalable Vector Graphics)是一种矢量图格式,它能够提供高质量、无损缩放的图像,非常适合用在多种分辨率的Android设备上。...
因此,对于大分辨率的图片,必须谨慎处理,防止一次性加载整个图片到内存中。 二、BitmapFactory与Options BitmapFactory是Android提供的一个用于解码图片的类,可以用来从各种数据源(如资源、文件或流)创建...
在Android应用开发中,处理超长图片是一项挑战,因为这些图片可能会导致内存溢出或性能下降。本测试Demo是基于“subsampling-scale-image-view”类库,它专门用于高效加载和显示大尺寸、高分辨率的图像,从而避免了...
图片会被加载到内存中,如果内存不足,最近不常使用的图片会被替换到磁盘上。 6. **图片加载库** 可能还使用了第三方的图片加载库,如Glide或Picasso,它们提供了更高效的图片加载、缓存和占位符等特性。这些库...
Android-Universal-Image-Loader是一个强大的、灵活的图片加载库,它具有异步加载、内存和磁盘缓存、错误处理、图片占位符等功能。该库由Sergey Tarasevich创建并维护,它支持多种图片格式,如JPEG、PNG、GIF等,...
这可能包括使用低分辨率的缩略图预加载,懒加载策略,以及利用内存缓存和磁盘缓存来减少I/O操作。项目中可能实现了这些策略,以确保应用在各种设备上都能流畅运行。 5. **适配器(Adapter)模式** 通常,为了将数据...
在Android平台上,结合OpenCV和ncnn库实现图片人像换背景及实时摄像头抠像是一项技术密集型的任务。本文将详细介绍这一过程中的关键知识点,并提供一个基础的资源准备指南。 首先,OpenCV是一个强大的计算机视觉库...
当加载大尺寸的图片时,如果直接将其加载到内存中,会占用大量内存,容易超过分配的内存限额,从而导致程序崩溃。为了避免这种情况,开发者需要采用一些优化策略。 1. **Bitmap对象的合理使用**:Bitmap是Android中...
综上所述,"Android-Android图片选择器支持图片或gif单个和多个图片选择"项目涵盖了Android开发中的多个关键领域,包括UI设计、多媒体数据处理、权限管理、图片加载库的运用以及性能优化等。通过理解和实现这些技术...
9. **性能优化**:考虑到Android设备的多样性,项目可能对低内存设备进行了优化,例如,采用延迟加载策略,只在图片进入视口时才加载,或者使用低分辨率的缩略图代替原图。 总的来说,"Android-PhotoMedia-master...
- 选择“ISO文件”作为启动源,并加载之前下载的Android-x86-4.0-RC2 ISO镜像。 ##### 2. 启动虚拟机并选择安装模式 - 启动虚拟机后,按`Alt + F1`进入文本模式。 - 在文本模式下,选择安装选项,通常会看到类似`...
HDImageView的核心功能在于它优化了图片的加载和显示过程,避免了由于大图直接加载到内存中导致的内存溢出问题。它可能采用了以下技术: 1. **图片压缩**:在加载图片之前,先对其进行压缩处理,减少内存占用,防止...
在Android应用开发中,图片的显示、选择以及手势...通过`Android-MultiselectPhotoView`,开发者可以快速构建出具有图片多选和手势操作功能的图片浏览模块,极大地提高了开发效率,同时也为用户带来了流畅的交互体验。
在Android开发中,加载大分辨率图片到手机内存中是一个常见的挑战,因为这可能导致内存溢出问题,特别是对于内存有限的移动设备。堆内存是每个Android应用程序可以使用的内存区域,其大小受到系统的严格限制,通常在...