Android开发中Bitmap高效加载使用详解

由于Android对单个应用所施加的内存限制,比如16MB,这导致加载Bitmap的时候很容易出现内存溢出,本文主要包含2个方面的内容分析Bitmap内存和Bitmap高效加载

一、占用内存

获取bitmap的内存,android提供的方法bitmap.getByteCount()
假如现在mipmap-xhdpi 目录下,有一个 200 * 200 像素的图片,运行加载它,看它输出的尺寸。

Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.btn_go);
bitmap.getByteCount()的输出结果为360000
现在把图片转移到mipmap-xxhdpi 中
bitmap.getByteCount的输出结果为160000
那么mipmap-xhdpi 目录下为何会大这么多呢?

density 影响 Bitmap 内存
放在不同的 mipmap 目录下,对应的不同 density 的设备。density 是设备的固有参数,伴随着 density 的,还有 densityDpi,它也是与设备相关的,表示屏幕每英寸对应多少个点(非像素点)

上面是官方提供的一张比较经典的图,可以看到,不同的目录,代表不同的 density ,例如 xhdpi 代表的 density 就是 2。而这里的 density 对 densityDip 的基准是 160 ,也就是说,mdpi 对应的 densityDpi 是 160 ,xhdpi 对应的 densityDpi 是 320,同样xxhdpi对应的densityDpi是480

density 和 densityDpi 在 Android 中,都有标准的 API 可以拿到,如下。

DisplayMetrics displayMetrics=new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
Log.i(TAG, displayMetrics.densityDpi+"");
Log.i(TAG,displayMetrics.density+"");

这是我手机的输出结果

densityDpi:480
density:3.0

从getByteCount()源码得知,Bitmap.getByteCount() 是由:
(bitmapWidth * scale) * (bitmapHeight * scale) *(每像素所占字节大小)得出来的
其中:int scale = phoneDensity / inDensity
phoneDensity是我们手机的densityDpi,上述得出我手机是480
inDensity是你图片存放的路径,比如xhdpi是320,xxhdpi是480
BitmapFactory默认色彩度为 ARGB_8888 图片,每像素会占用 4 bytes
在xhdpi下:200 * (480/320) * 200(480/320)4= 360000
在xxhdpi下:200 * (480/480) * 200(480/480)4= 160000

以上就是bitmap所占内存分析。

二、高效加载

1.修改bitmap.config
2.修改inSampleSize

bitmap.config简介

上面提到BitmapFactory默认色彩度为 ARGB_8888

Bitmap.Config一共有四个参数如下:
(这些参数决定了Bitmap位图的配置,会影响到bitmap的像素如何、色彩、以及是否有透明度的能力)

Bitmap.Config ALPHA_8

这个参数每个像素占用1字节的空间。
它代表每个像素点被存储为单个透明度的通道,这对于设置遮罩的图片用例十分有用,它不存储颜色信息。

Bitmap.Config RGB_565

这个参数每个像素占用2字节的空间。
它代表只有RGB通道的编码,其中红色占用5位地址,绿色占用6位地址,蓝色占用5位地址。没有透明度的通道。
使用不透明的位图时,不要求高的色彩保真度使用此配置是不错的选择。

Bitmap.Config ARGB_4444

这个参数每个像素占用2字节的空间。
它一共有四个通道,顾名思义,分别是透明度、红、绿、蓝。每个通道分别占用四位地址,所以一共2字节。
当应用需要节省内存(对色彩质量要求低),同时又需要存储透明度信息,这个配置可以作为选择,但官方比较推荐用ARGB_8888的设置,因为这个的色彩质量差。

Bitmap.Config ARGB_8888

这个参数每个像素占用4字节的空间。
这也是一共4个通道,但不一样的是每个通道站8位地址,因而色彩质量比上一个设置高了特别特别多(16倍)。
能够满足最好的位图质量,在内存充足的情况下,十分推荐使用这个。

inSampleSize简介

通过BitmapFactory.Options来缩放图片,主要是用inSampleSize参数,当inSampleSize=1时,采样后的图片为图片的原始大小,当inSampleSize=2时,采样后的图片宽,高均为原图大小的1/2,而像素数为原图的1/4,假定图片原有的内存是4MB,如果把它的inSampleSize设为2,它的内存就会变成1MB
具体实现代码如下

 public static Bitmap decodeBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight){
  final BitmapFactory.Options options=new BitmapFactory.Options();
  options.inJustDecodeBounds=true;
  BitmapFactory.decodeResource(res,resId,options);
  options.inSampleSize=1;
  options.inSampleSize=setInSampleSize(options,reqWidth,reqHeight);
  options.inPreferredConfig= Bitmap.Config.ARGB_4444;
  options.inJustDecodeBounds=false;
  return BitmapFactory.decodeResource(res,resId,options);
 }

 public static int setInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
  final int height=options.outHeight;
  final int width=options.outWidth;
  int inSampleSize=1;
  if(height>reqHeight||width>reqHeight){
   final int halfHeght=height/2;
   final int halfWidht=width/2;
   while ((halfHeght/inSampleSize>=reqHeight)&&(halfWidht/inSampleSize>=reqWidth)){
    inSampleSize *=2;
   }
  }
  return inSampleSize;
 }

有了上面两个方法,实际使用就简单了,比如imageView所期望的图片大小为100X100,这个时候我们就可以这样调用,还是之前存放在xxhdpi中的图片,上述代码中已经把bitmap.config设置成ARGB_4444 ,现在把原先尺寸200X200改成100X100,看下内存是多少

Bitmap bitmap=
decodeBitmapFromResource(getResources(),R.mipmap.btn_go,100,100);
Log.i(TAG,bitmap.getByteCount()+"");

bitmap.getByteCount的输出结果为20000,比之前160000减少了8倍, ARGB_4444较ARGB_8888减少了2倍,设置尺寸100,100传入setInSampleSize()方法中得到inSampleSize=2, 像素数为原图的1/4,内存大小总共就变成了之前的1/8,这样高效加载图片,就会远离oom。

您可能感兴趣的文章:

  • Android Bitmap详细介绍
  • Android Activity之间传递图片(Bitmap)的方法
  • android bitmap compress(图片压缩)代码
  • android保存Bitmap图片到指定文件夹示例
  • Android截取视频帧并转化为Bitmap示例
  • android中Bitmap的放大和缩小实例代码
  • android将Bitmap对象保存到SD卡中的方法
  • 解析Android开发优化之:对Bitmap的内存优化详解
  • Android读取本地或网络图片并转换为Bitmap
  • Android界面 NotificationManager使用Bitmap做图标
(0)

相关推荐

  • Android读取本地或网络图片并转换为Bitmap

    在做android项目时,我们经常需要从本地或者网络读取图片,并转换为Bitmap图片,以便使用,下面是读取本地图片并转换的方法: Java代码 /** * 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如: * * A.网络路径: url="http://blog.foreverlove.us/girl2.png" ; * * B.本地路径:url="file://mnt/sdcard/photo/image.png"; * * C.

  • android bitmap compress(图片压缩)代码

    android的照相功能随着手机硬件的发展,变得越来越强大,能够找出很高分辨率的图片.有些场景中,需要照相并且上传到服务,但是由于图片的大小太大,那么就上传就会很慢(在有些网络情况下),而且很耗流量,要想速度快,那么就需要减小图片的大小.减少图片的大小有两种方法,1. 照小图片: 2. 压缩大图片. 照相时获取小图片一般不太符合要求,因为,图片的清晰度会很差,但是这种情况有个好处就是应用速度会快些: 压缩图片,就是把大图片压缩小,降低图片的质量,在一定范围内,降低图片的大小,并且满足需求(图片仍

  • android中Bitmap的放大和缩小实例代码

    复制代码 代码如下: /**Bitmap放大的方法*/ private static Bitmap big(Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.postScale(1.5f,1.5f); //长和宽放大缩小的比例 Bitmap resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true); return

  • Android Activity之间传递图片(Bitmap)的方法

    在Android开发中:Activity之间传递参数是常见的事:如果我们要在Activity之间传递图片:1.MainActivity中包括一个ImageView:当我们点击ImageView时:把图片传递给另外一个Activity MainActivity的主要代码: 复制代码 代码如下: Intent intent=new Intent(MainActivity.this,TranActivity.class);            intent.putExtra("bitmap"

  • 解析Android开发优化之:对Bitmap的内存优化详解

    1) 要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间.那为什么还需要这个方法呢? Bitmap类的构造方法都是私有的,所以开发者不能直接new出一个Bitmap对象,只能通过BitmapFactory类的各种静态方法来实例化一个Bitmap.仔细查看BitmapFactory的源代码可以看到,生成Bitmap对象最终都是通

  • Android Bitmap详细介绍

    复制代码 代码如下: package com.testbitmapscale; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import com.testbitmapscale.R.drawable; im

  • Android界面 NotificationManager使用Bitmap做图标

    今天看到EOE问答里面有这"[Android 界面]NotificationManager 如何使用Bitmap做图标"这样一个问题,在论坛搜索也没有好的案例 特写一个简单的demo供大家参考 今天发布的是NotificationManager 使用Bitmap做图标 关键code 复制代码 代码如下: public void notification(int flag) { Notification notification = new Notification(); //设置sta

  • android将Bitmap对象保存到SD卡中的方法

    本文实例讲述了android将Bitmap对象保存到SD卡中的方法.分享给大家供大家参考.具体如下: Bitmap logoBitmap = BitmapFactory.decodeResource(mcontext.getResources(), R.drawable.arcnote_logo); ByteArrayOutputStream logoStream = new ByteArrayOutputStream(); boolean res = logoBitmap.compress(B

  • Android截取视频帧并转化为Bitmap示例

    MainActivity如下: 复制代码 代码如下: package cn.testmediametadataretriever; import java.io.File; import java.io.FileOutputStream; import android.media.MediaMetadataRetriever; import android.os.Bundle; import android.os.Environment; import android.app.Activity;

  • android保存Bitmap图片到指定文件夹示例

    复制代码 代码如下: /** 保存方法 */ public void saveBitmap() { Log.e(TAG, "保存图片"); File f = new File("/sdcard/namecard/", picName); if (f.exists()) { f.delete(); } try { FileOutputStream out = new FileOutputStream(f); bm.compress(Bitmap.CompressFor

随机推荐