一、BitmapFactory.decodeStream()方法


    尽量不要使用setImageBitmap()、setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些方法在完成decode后,最终都是通过Java层的createBitmap()来完成的,需要消耗更多内存资源。


     因此,可以使用先通过BitmapFactory.decodeStream()方法创建出一个Bitmap,再将其设为ImageView的source的方法。


    BitmapFactory.decodeStream()方法最大的秘密在于,其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用Java层的createBitmap,从而节省了Java层的空间。



二、BitmapFactory.Options


    当图片过大或图片数量较多时,使用BitmapFactory解码图片会出java.lang.OutOfMemoryError: bitmap size exceeds VM budget,要想正常使用则需分配更少的内存,具体的解决办法是修改采样值BitmapFactory.Options.inSampleSize,例如:


BitmapFactory.Options opts = new BitmapFactory.Options();opts.inSampleSize = 4;Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);


    查看官方的文档说明:



    简单翻译一下:

    如果设置的值大于1,则要求解码器从原始图片中采样一张小图,以此来节省内存消耗。例如,inSampleSize的值为4时,则解码器返回图片的宽高是原始图片的1/4,也就是说,返回图片的像素点数量是原始图片的1/16。任何小于1的值都会被当成1。

    注意:解码器会尽可能满足采样请求,但有时候返回结果会和原来的精确请求有所差异;把值设置为2对解码器来说是最快最容易满足的。

    因此,如何正确设置恰当的inSampleSize是解决该问题的关键之一。

    

    BitmapFactory.Options提供了另一个成员变量inJustDecodeBounds。例如:


BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);


    查看官方的文档说明:


    

    简单翻译一下:

    如果设置为true,解码器会返回null,但图片的外围边界值仍然可以得到,这就允许调用者在无需分配内存加载图片的情况下获取图片的相关信息。

    设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。


    查看Android源码,Android提供了一种动态计算的方法。


public static int computeSampleSize(BitmapFactory.Options options,        int minSideLength, int maxNumOfPixels) {int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);int roundedSize;if (initialSize <= 8 ) {roundedSize = 1;while (roundedSize < initialSize) {roundedSize <<= 1;}} else {roundedSize = (initialSize + 7) / 8 * 8;}return roundedSize;}private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {double w = options.outWidth;double h = options.outHeight;int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));if (upperBound < lowerBound) {// return the larger one when there is no overlapping zone.return lowerBound;}if ((maxNumOfPixels == -1) && (minSideLength == -1)) {return 1;} else if (minSideLength == -1) {return lowerBound;} else {return upperBound;}}

    使用该算法,就可动态计算出图片的inSampleSize。

    

    完整过程如下:


BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(imageFile, opts);opts.inSampleSize = computeSampleSize(opts, -1, 128*128);opts.inJustDecodeBounds = false;try {Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);imageView.setImageBitmap(bmp);    } catch (OutOfMemoryError err) {}


    另外,可以通过Bitmap.recycle()方法来释放位图所占的空间,当然前提是位图没有被使用。



三、优化Dalvik虚拟机的堆内存分配


    对Android平台来说,其托管层使用的Dalvik Java VM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。

    当然具体的做法可以参考开源工程,这里仅说下使用方法,在程序onCreate()时调用即可 : 


private final static float TARGET_HEAP_UTILIZATION = 0.75f;VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 


四、自定义Android堆内存大小


    对一些Android项目来说,影响性能的主要瓶颈是Android自身的内存管理机制问题,目前手机厂商对RAM都比较吝啬,对软件的流畅性来说,RAM对性能的影响十分敏感,除了优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件对内存的要求大小,我们使用Dalvik提供的dalvik.system.VMRuntime类来设置最小堆内存:


// 设置最小Heap内存为6MBprivate final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); 


    当然对于内存吃紧,还可以通过手动干涉GC去处理。



参考资料:

http://www.maxhis.info/archives/491








更多相关文章

  1. Android平台使用MediaCodec进行H264格式的视频编解码
  2. android微信纯图片分享和网页分享
  3. 内存3
  4. andorid中网络图片下载、保存以及在相册中显示
  5. android 通过Intent打开相册并获取选择的图片
  6. Android学习笔记(21):ImageView及其子类
  7. android应用程序内存分析
  8. Android中的图像处理
  9. Android(安卓)实现多图分享到微信朋友圈

随机推荐

  1. android基本的数据库创建和使用
  2. 你知道 Android 的 MessageQueue.IdleHan
  3. Android开发错误Unable to execute dex:
  4. Android/OPhone开发完全讲义
  5. Android 自动化测试—robotium(八)拖拽
  6. Android API 28 访问服务器失败 提示CLEA
  7. android 串口通信选择
  8. 制作ota升级包之error:Could not create t
  9. EditText 属性
  10. Android 面试之 Android 篇一