(DOC)Displaying Bitmaps Efficiently
本人才疏学浅,翻译的不对的地方请指出,而且本人不是针对原文一字一句翻译的,适当作些调整,翻译大概意思,并添加一些小批注。这些文章提供了一个可行的解决办法,适合初学者应用,它介绍了各种处理图片的方式,可以应用在程序中,未必是完美的。Displaying Bitmaps Efficiently这是文档中的新的一部分:大概翻译下内容:这章覆盖了一些常用的技术,是关于处理Bitmap对象的,可以帮助您的UI快速响应,避免内存溢出。如果您不小心,可能很快地消耗了内存,导致程序的崩溃。抛出异常:java.lang.OutofMemoryError: bitmap size exceeds VM budget.关于为什么在Android应用在加载Bitmap时有限制,主要有以下几点:移动设备只有有限的系统资源,Android设备只有16mb可用于一个程序。android compatibility definition document(CDD)[url]http://source.android.com/compatibility/downloads.html [/url],第三节Virtual Machine Compatility 给出了不同屏幕和分辨率的最小应用内存需求说明,应用程序需要在这样的内存限制中优化。Bitmap会消耗很多的内存,尤其像照片,摄像头在GalaxyNexus拍一张照片有2592*1936像素,如果bitmap使用ARGB_8888配置(2.3默认的),加载这张照片到内存需要消耗约19mb内存,(2592*1936*4bytes)。就超过了应用的内存限制了。android的ui经常需要加载几张bitmap位图,像ListView,GridView,ViewPager这样的组件在屏幕上通常会有多张的位图。Loading Large Bitmaps Efficiently图片有各种大小,开状,多数情况下对于特定的android程序ui来说它们是偏大的。如Gallery应用显示照片跟摄像头的比就小得多了。在内存受限的情况下,你只需要加载一些低分辨率的图片,一张大分辨率的图片并没有提高视觉效果,还占用更多的内存,这节告诉您如何解码大的图片,而不超过系统的限制。Read Bitmap Dimensions and TypeBitmapFactory类提供了一些解码的方法decodeByteArray(),decodeFile(),decodeResource()等,来创建一个位图资源。需要选择正确的方法来解析图片资源。这些方法会构造一个位图,然后申请内存,容易造成oome,每一个方法都有一个额外的信息为您 分配解码选项BitmapFactory.Options类,设置inJustDecodeBounds属性为true时,解码避免了内存占用,它不会返回位图信息,而设置了outWidth,outHeight,outMimeTYpe。这些就可以供读取解析度与类型了。BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(getResources(), R.id.myimage, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;String imageType = options.outMimeType;避免oome的出现可以先判断dimensions,再解码Load a Scaled Down Version into Memory加载一个缩放后的版本到内存中,位图的dimensions从上面得到后,可用于决定是否位图可以加载到内存,或加载一个缩放后的版本。这里给出一些因素供参考:估计内存的消耗。计算应用的其它部分占用的内存与当前图片应该占用的内存。贴图目标需要多大的dimensions,如ImageView,或其它ui。屏幕的大小与解析度。如,显示在128x96像素的ImageView中不值得加载一个1024*768像素的图片。在BitmapFactory.Options 设置inSampleSize的值就可以改变了。如2048*1536像素的图片解码时inSampleSize=4,就会得到一个512*384大小的位图了,使用0.75mb内存,而不是12mb。下面提供一个方法来计算 :public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { if (width > height) { inSampleSize = Math.round((float)height / (float)reqHeight); } else { inSampleSize = Math.round((float)width / (float)reqWidth); } } return inSampleSize;}注意:使用2的倍数会对解码更高效的(我估计是二进制的原因),使用这个方法,首先需要options.inJustDecodeBounds = true;先解码一次,然后再使用新的inSampleSize值,options.inJustDecodeBounds = false来解码需要的图片。public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options);}这就提供了简易的加载图片的方法了:mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));剩下两篇下面继续