Android | Bitmap解析

Android中Bitmap是对图像的一种抽象。通过他可以对相应的图像进行剪裁,旋转,压缩,缩放等操作。这里循序渐进的一步步了解Bitmap的相关内容。

先了解Bitmap相关的API,然后根据API进一步了解内部的实现。


1.生成Bitmap--BitmapFactory

android.graphics.Bitmap.java

 /**
* Private constructor that must received an already allocated native bitmap
* int (pointer).
*/
// called from JNI Bitmap类中只有一个构造器。而且还不能直接调,必须通过JNI去构造
Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
boolean isMutable, boolean requestPremultiplied,
byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
...
}

Bitmap类中只有一个构造器。而且还不能直接调,必须通过JNI去构造。源码中已经写的很清楚。所以一定有JNI的方式产生Bitmap对象。这就是BitmapFactory的功能--生成Bitmap

android.graphics.BitmapFactory.java

	/**
* Creates Bitmap objects from various sources, including files, streams,
* and byte-arrays.
*/
public class BitmapFactory {
...
}

通过这个类可以看到所有的方法都是静态方法。而且支持从文件,流,字节数组等各种资源中获取Bitmap对象。

从结构图可以看出生成Bitmap的方式有四大类:

decodeFile 从文件系统加载

decodeResource 以R.drawable.xxx的形式从本地资源中加载

decodeStream 从输入流加载

decodeByteArray 从字节数组中加载

其中decodeFile和decodeResource间接调用decodeStream方法。而且返回Bitmap使用前要判空,在不存在的情况下会返回null.

每一种decodeXXX方法最后都有一个Options对象。这个对象的作用就是在decode解压到内存之前的一些可选项。利用这些可选项可以优化内存,以及展示的效果等。

Options是BitmapFactory的静态内部类

常用的配置有:

inPreferredConfig | 指定位图编码格式 可选项在Bitmap.Config中,缺省值是ARGB_8888。

inJustDecodeBounds | true 返回的Bitmap将是null,但是Options的outAbc中解出了图像的基本信息

inSampleSize | 采样率,设置缩放比例.采样率就是抽取像素点组成位图,采样率同时作用于宽和高。

比如inSampleSize为2,采样后的图片的宽高均为原始图片宽高的1/2,这时像素=原始图片的1/4,占用内存=原始图片的1/4;

inSampleSize的取值应该总为2的整数倍,否则会向下取整,取一个最接近2的整数倍,比如inSampleSize=3时,系统会取inSampleSize=2

假设一张10241024,模式为ARGB_8888的图片,inSampleSize=2,原始占用内存大小是4MB,采样后的图片占用内存大小就是(1024/2) * (1024/2 ) 4 = 1MB

备注:

ALPHA_8:每个像素占用1byte内存。

ARGB_4444:每个像素占用2byte内存

ARGB_8888:每个像素占用4byte内存(默认为改格式)

RGB_565:每个像素占用2byte内存

所以默认一张1024*1024像素的位图是4MB的,如果硬生生加载进内存会占用很大一块。很容易造成OOM!因此就需要Options去提前配置一下。


2.Bitmap方法对自身的变换

Bitmap可以和Matrix结合实现图像的剪切、旋转、缩放等操作,最终调用到的createXXXBitmapXXX方法有下面几个:

他们最终都会调用native方法:

//////////// native methods

private static native Bitmap nativeCreate(int[] colors, int offset,
int stride, int width, int height,
int nativeConfig, boolean mutable);

可见他们的变换本质都是一样的。只是调用的方式不同

用源Bitmap通过变换生成新的Bitmap的方法:

public static Bitmap createBitmap(Bitmap source, int x, int y, intwidth, int height,
Matrix m, boolean filter) //最终的实现,后两种只是对第一种方法的封 ,
//设置Matrix的Rotate(通过setRotate())或者Scale(通过setScale()),传入第一个方法,可实现旋转或缩放。 public static Bitmap createBitmap(Bitmap source, int x, int y, intwidth, int height)
//可以从源Bitmap中指定区域(x,y, width, height)中挖出一块来实现剪切 public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
int dstHeight,boolean filter)
//可以把源Bitmap缩放为dstWidth x dstHeight的Bitmap

用于压缩到流的方法:

public boolean compress(CompressFormat format, int quality, OutputStream stream)
//format指定压缩的格式:
一共三种
JPEG (0),
PNG (1),
WEBP (2);
//quality指定压缩品质0-100可输入。0是最差,100是无损。PNG格式压缩会忽略这个选项
//stream 压缩输出的流在这里取出,接下去可以对流进行操作 public Bitmap copy(Config config, boolean isMutable)
//这个方法主要用于复制出一个全新的位图。Config指定新位图格式ALPHA_8, RGB_565, ARGB_4444, ARGB_8888,
//isMutable, true表示产生的位图无法更改

3.使用Bitmap需要注意的问题

1.最常见的问题OOM

及时释放内存

if (!bmp.isRecycle()) {
bmp.recycle(); //回收图片所占的内存
bitmap = null;
system.gc(); //提醒系统及时回收
}

recycle()并不保证立即释放占用的内存,但是可以加速内存的释放。

释放内存以后,就不能再使用该Bitmap对象了,否则会抛异常。所以一定要保证不再使用再释放。比如,如果是在某个Activity中使用Bitmap,建议在Activity的onStop()或者onDestroy()中进行回收。

内存中混存通用Bitmap避免多次加载。

比如默认图片可以只加载一次然后一个界面内多处使用。

2.图片压缩

inSampleSize压缩是尺寸压缩,compress方法是质量压缩。

compress方法在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,经过它压缩的图片文件存储大小会改变,但导入成bitmap后占内存大小不变,宽高也不会改变。

Android笔记--Bitmap的更多相关文章

  1. Android笔记——Bitmap自动取色(纯搬运)

    2015/6/12更新:发现一个更好的,带demo https://github.com/MichaelEvans/ColorArt 说明: 这个是一个老外写的自动自动从bitmap中取主色与第二主色 ...

  2. Android笔记--Bitmap(三) 针对不用Android版本的位图管理

    Bitmap(三) | Android不同版本的相应操作 在不同的Android版本中.位图的存储方式是不同的. 1.小于等于 Android 2.2 (API level 8) 垃圾收集器回收内存时 ...

  3. Android笔记--Bitmap(二)内存管理

    Bitmap(二) 内存管理 1.使用内存缓存保证流畅性 这种使用方式在ListView等这种滚动条的展示方式中使用最为广泛, 使用内存缓存 内存缓存位图可以提供最快的展示.但代价就是占用一定的内存空 ...

  4. Android笔记--自定义控件仿遥控器的圆形上下左右OK圆盘按钮

    原文:Android笔记--自定义控件仿遥控器的圆形上下左右OK圆盘按钮 上面就是几张预览图!代码在最底下 主要就两个步骤,画图.监听点击 1.整个控件基本上是一步步画出来的,重写onDraw方法开始 ...

  5. Android笔记——Matrix

    转自:http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#translate Matrix的数学原理 在Android中,如果你 ...

  6. Android笔记——Android自定义控件

    目录: 1.自定义控件概述 01_什么是自定义控件 Android系统中,继承Android系统自带的View或者ViewGroup控件或者系统自带的控件,并在这基础上增加或者重新组合成我们想要的效果 ...

  7. int android.graphics.Bitmap.getRowBytes()

    int android.graphics.Bitmap.getRowBytes() Return the number of bytes between rows in the bitmap's pi ...

  8. Android笔记——Android中数据的存储方式(二)

    我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...

  9. Android中Bitmap, Drawable, Byte,ID之间的转化

    Android中Bitmap, Drawable, Byte,ID之间的转化 1.  Bitmap 转化为 byte ByteArrayOutputStream out = new ByteArray ...

随机推荐

  1. 十张Gif动图让你弄懂递归等概念

    图像(包括动图)是传递信息的一种高效方式,往往能增强表象.记忆与思维等方面的反应强度.所谓一图胜千言,说的就是这个道理. 今天为大家整理了十张动图GIFS,有助于认识循环.递归.二分检索等概念的具体运 ...

  2. 【eclipse插件开发实战】 Eclipse插件开发5——时间插件Timer开发实例详解

    Eclipse插件开发5--时间插件Timer开发实例详解 这里做的TimeHelper插件设定为在菜单栏.工具栏提供快捷方式,需要在相应地方设置扩展点,最后弹出窗体显示时间. 在上一篇文章里创建好了 ...

  3. Java简单的数组用法尝试,和C语言很不一样

    public class Main { static int ARRY_LONGTH=100; static int[] getRandomArr(int n){ int[] randomArr; r ...

  4. Win7 server2008 共享文件夹 不输入网络密码

    如何设置共享文件夹访问不需要输入用户名和密码: 1.“开始”——“运行”——secpol.msc (1)使用空白密码的本地帐户只允许进行控制台登录 禁用它 (2)“本地策略”——“安全选项”——“网络 ...

  5. jade安装及基本语法使用

    一.cmd安装jade: cnpm install -g jade //cnom install jade -g与上面使用效果一致. 二.jade命令行中使用: 使用cmd: jade index.j ...

  6. [Xcode 实际操作]一、博主领进门-(5)检测运行中的模拟器在各个方向上的切换

    目录:[Swift]Xcode实际操作 本文将演示Xcode的设备模拟器在各个方向上的切换和检测. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] 检测运行中的模拟 ...

  7. [Xcode 实际操作]八、网络与多线程-(17)使用网址会话对象URLSession向远程服务器上传图片

    目录:[Swift]Xcode实际操作 本文将演示如何通过网址会话对象URLSession向远程服务器上传图片. 网址会话对象URLSession具有在后台上传和下载.暂停和恢复网络操作.丰富的代理模 ...

  8. js中 call() ,apply(),bing()方法三者的用法和区别

    面试中经常会被问到的,或者做笔试题的时候也会有这样的问题,所以今天专门对这个问题做个总结: 先看个例子: var age = '19' var myObj = { name:'小赖', myAge:t ...

  9. 要单独拿出来讲的a标签

    a标签的属性 href属性赐予a标签力量:href属性指定要通过a标签借助浏览器请求的资源,可以是图片.视屏.网站.音频等.不加herf属性的a标签就是一个没有任何特殊样式和功能的文本容器. targ ...

  10. NOIp2016 愤怒的小鸟 【状压dp】By cellur925

    题目传送门 注:本文中绿鸟==猪! 这道题开始一看数据范围我们就知道是一道状压dp,因为绿鸟仅有18个,但是开始看\(m\)好像没太懂什么意思.既然确定了是状压,那就来设计状态,一般状压的状态肯定是要 ...