Android中的Bitmap和Drawable分析

最近比较闲,开始整理下接触到的东西吧,加深一下对一些知识点的认识,一直对Android中的Bitmap和Drawable认识比较模糊,用起来也是迷迷糊糊的,所以首先对这两个类做一些分析吧(一般我们可以在官网上查看相关api或是直接在AS里面点进去查看类的源码)
1. Bitmap 与 Drawable区别 


    首先看看Drawable类的注释
    >   A Drawable is a general abstraction for "something that can be drawn." 
    >   Most often you will deal with Drawable as the type of resource retrieved for
    >   drawing things to the screen; the Drawable class provides a generic API for
    >   dealing with an underlying visual resource that may take a variety of forms.
    >   Unlike a {@link android.view.View}, a Drawable does not have any facility to
    >   receive events or otherwise interact with the user.


    Drawable是一个抽象类,代表的是“可绘制的东西”的一般抽象。通常你会将Drawable作为绘制事物到屏幕上的资源类型来处理,它提供了一个通用API来处理可能采用多种形式的底层视觉资源。与View不同的是,Drawable没有任何接收事件或以其他方式与用户交互的功能。平常我们使用的时候都是res目录下创建相应的drawable资源,比如button的背景图片,背景颜色,以及button不同的状态的动画效果等。
    
    然后接着看下面一段注释
    
    Though usually not visible to the application, Drawables may take a variety of forms:
    
    >   Bitmap: the simplest Drawable, a PNG or JPEG image.
    
    >   Nine Patch: an extension to the PNG format allows it to specify information about how to stretch it and place things inside of it.
    
    >   Vector: a drawable defined in an XML file as a set of points, lines, and curves along with its associated color information. This type of drawable can be scaled without loss of display quality.
    
    >   Shape: contains simple drawing commands instead of a raw bitmap, allowing it to resize better in some cases.
    
    >   Layers: a compound drawable, which draws multiple underlying drawables on top of each other.
    
    >   States: a compound drawable that selects one of a set of drawables based on its state.
    
    >   Levels: a compound drawable that selects one of a set of drawables based on its level.
    
    >   Scale: a compound drawable with a single child drawable, whose overall size is modified based on the current level.
    
    这段话说的意思是,虽然Drawable通常对于应用来说是不可见的,但是它可以采取多种形式。如Bitmap, Shape, Layers等。 看到这里还以为Bitmap是继承自Drawable但是并不是,我们来看看Bitmap这个类:
    
    ```
    public final class Bitmap implements Parcelable {
        ...
    }
    ```
    这个类是继承的Parcelable,它存储的是图片相关的信息。这里另外说一个类BitmapDrawable,它是直接继承自Drawable。通过这个类可以实现Drawable和Bitmap之间的相互转换。
        
    ```
    //bitmap转drawable
    Drawable drawable = new BitmapDrawable(bmp);
    
    //drawable转bitmap
    Drawable drawable = gerResource().getDrawable(R.drawable.ic_launcher);
    BitmapDrawable bpDrawable = (BitmapDrawable) drawable;
    Bitmap bm  = bpDrawable.getBitmap();
    
    ```


    
 Bitmap代表的是一种视觉资源,侧重于一种数据类型;而Drawble则是提供了一些API来处理这些资源,侧重于行为。


2. Drawable分类与相关API
    
    前面提到过,Drawble通常对应用是不可见的,但是它可以采取多种形式,我的理解是对每种不同的资源都有一个对应的drawable的实现去处理.例如BitmapDrawable, ShapeDrawable, LayerDrawable等
    
    可以看一下Android中Drawable的继承结构,如下图所示:

   
    具体每个类什么意思就不一一说了,好多我也没用过。只说一下Drawable类本身的一些API代表着什么意思:
    
    -  setBounds()
    
    这个方法传入一个Rect,为Drawable指定一个边界矩形。这个Rect就是drawable在调用draw()方时绘制的地方。


    -  getIntrinsicWidth()
    返回drawable的固有宽度,包括固有的padding值。一般像一张图片所形成的drawable会返回图片的宽,而像颜色之类的drawable会返回-1。getIntrinsicHeight同理。
    
    -  createFromXmlInner() 
    
    这个方法就是从xml文件中创建一个Drawable对象。还有一系列的createFromxxx方法。这个createFromXmlInner方法会调用到DrawableInflater类里的inflateFromTag方法,这个方法就会根据我们在xml中的根标签创建不同的drawable对象。例如:根标签是“selector”,就会创建StateListDrawable对象,根标签是“animated-selector”,就会创建AnimatedStateListDrawable对象。


    - inflate()
    
    从xml资源文件中解析属性,每个drawable对象只能调用一次,一般Framework在从xml资源中创建Drawable实例的时候已经调用过了。
    
    - draw()
    
    把之前设置了Bounds, alpha值等的drawable画到canvas上。如果要自定义Drawable通过需要重写draw()方法


3. Bitmap相关配置与加载
    
    Bitmap
    1. Bitmap.CompressFormat 与 Bitmap.Config 
    
        CompressFormat与Config是Bitmap的内部枚举类。其中CompressFormat指定位图可以压缩到的已知格式,而Config代表可能的位图配置。位图配置描述像素如何存储。 这影响质量(颜色深度)以及显示透明/半透明颜色的能力。


        CompressFormat的枚举值有JPEG, PNG, WEBP三种,都是比较常见的。而Config的枚举值有ALPHA_8, ARGB_4444, ARGB_8888, RGBA_F16, RGB_565, HARDWARE
    
        其中的字母意义是 A:透明度 R:红色 G:绿 B:蓝
        
        ALPHA_8:每个像素被存储在单一通道里,占一个字节,只有透明度,没有颜色。
        
        ARGB_4444:每个像素被存储在2个字节里,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位,由于这个配置下的图片质量太差已经被废弃


        ARGB_8888:每个像素被存储在4个字节里,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
        
        RGBA_F16:每个像素被存储在8个字节里。
        
        RGB_565:每个像素被存储在2个字节里,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
        
        HARDWARE:这是一种特殊的配置,bitmap被存储在graphic memory里使用这个配置。


        一般来说,每个像素占用的空间越大,图片的品质就越高,但是这样相应占用的内存也就越大。如果我们对于图片的要求不是那么高的话可以选择使用RGB_565。


    2. Bitmap的常见API
        
        - getWidth()
        
        获取bitmap的宽度,getHeight()用来获取高度
        
        - getRowBytes()
        
        获取Bitmap每一行所占用的空间数,可以用getRowBytes()*getHeight来获取bitmap大小,文档上说不应该用这个方法来获取bitmap大小,而是使用getAllocationByteCount()
        
        - getByteCount()
        
        获取可以存储此bitmap像素的最小字节数,看源码,这个方法内部调用了getRowBytes() * getHeight()。同样获取大小也不应该使用该方法
        
        - getAllocationByteCount()
        
        获取用来存储bitmap像素所分配的内存大小。如果这个bitmap被重用来解码更小尺寸的其它位图,这个值可能会比getByteCount获取的值大一些。在bitmap的生命周期内此值不会改变。
        
        - isMutable()
        
        返回bitmap是否易变的,即bitmap是否可以被修改或写入,例如在调用setConfig时,我会先调用该方法,如果返回false,则调用setConfig时会出错。
        
        - setConfig()
        
        给图片设置位图配置,设置的值就是前面介绍的Config的枚举值,之后bitmap就会按照配置值存储。一般默认是ARGB_8888, 如果对图片质量要求不高的话,设置成RGB_565后可以起到压缩图片的作用。
        
        - createBitmap
        
        从源bitmap的子集中返回一个不可变的bitmap。新的bitmap可能与源bitmap相同,也可能是源bitmap的一个副本。这个方法可以通过缩放源bitmap的宽高,来对源bitmap进行压缩。
        
        - createScaledBitmap
        
        通过对已存在的bitmap缩放来创建一个新的bitmap。需要注意的是,如果指定的宽高和原始bitmap的宽高一致的话,就会返回原始bitmap。我之前出的一个Bug就是,调用这个方法之后以为获取到的永远是新的bitmap,就把原始bitmap回收掉了,从而产生了空指针。这个方法和createBitmap其实原理都是一样的,它的内部就调用了createBitmap。可以通过缩放图片的宽高来达到压缩图片的效果,用来做缩放压缩。
        
        - compress()
        
        将bitmap按照指定的格式和质量参数压缩到输出流中,可以用来做质量压缩。需要注意的是,这个方法压缩的是存储的大小,而不是bitmap的内存大小,内存大小是不变的。我的理解是这个方法主要用于上传下载或保存时,减小文件体积,优化上传下载速度。如果想减小bitmap的内存占用,还是需要从像素字节,长和宽这三个因素来调整。另外PNG格式是无损的,不能用这个方法进行压缩。
        
        - isRecycled()
        
        判断bitmap是否被回收掉了,很多方法调用之前都要先调用这个方法判断一下,防止发生异常
        
    3. BitmapFactory
        Android中Bitmap的加载离不开BitmapFactory类,BitmapFactory类是Android提供的一个工具类,用于从不同的数据来源中解析创建Bitmap。数据来源包括,Resource, 文件,流,字节数组。主要方法如下:
        
        - decodeFile()
        
        - decodeResource()
        
        - decodeStream()
        
        - decodeByteArray()
        
        BitmapFactory中有一个非常重要的内部类Options,这个类就是用来配置加载的图片的相关信息的,Options中有几个很重要的值:
        
        - public Bitmap inBitmap
        
        设置Bitmap是否被重用,如果这个值被设置了,decode方法会在加载内容的时候去reuse已经存在的bitmap. 重用bitmap以便提升性能。
        
        - public boolean inJustDecodeBounds
        
        将该值设置为true时,我们并不会返回真正的bitmap,而是将bitmap的相关信息,如宽,高等放入options。这样你就可以根据原始图片的宽高和你需要的宽高来计算inSampleSize。然后再将inJustDecodeBounds的值设置为false, 来真正加载图片。
        
        - public int inSampleSize
        
        这个代表采样率。一般是大于1的数,例如这个值如果为2的话,那么采样后的图片宽高为原始图片的1/2。按照图片内存大小计算方法,内存就为原始图片的1/4。inSampleSize值小于1时会被当成1对待。
        
        - public int inDensity
        
        设置位图的像素密度,即每英寸有多少个像素
        
        上面一系列的decodeXXX方法都支持Options做为参数,我们可以通过设置Options来完成bitmap的加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值