Android-认识Bitmap

学习自

  • Android开发艺术探索

例行废话

在Android的各种APP中都被离不开各种各样的图片,有的图片很大,有的图片很小不管这样图片都是一种很吃内存的资源,而在Android中每个APP所持有的资源是非常有限的,所以我们要尽可能的“抠门”一点。本着能省则省的原则,有一个 300 x 300 的图片现在在一个100 x 100 的ImageView中是一个完全不必要的事情。所以我们为了更节省资源和避免OOM,我们必须对图片进行处理。在Android中 Bitmap 就代表一个图片资源。

BitmapFactory和Options

我们记载位图资源都是通过 BitmapFactory 进行加载的,这个类提供了以下的方法。

方法名 描述
decodeResource 从资源中加载图片
decodeByteArray 从byte数组中加载图片
decodeFile 从文件中加载图片
decodeStream 从流中加载资源

Options

Options类是BitmapFactory的一个嵌套类,所有的对Bitmap进行特殊处理的操作同时通过这个类的参数和属性达成的。其中一个Bitmap所占用的内存的大小是由下面的几个参数影响的。

  • inPreferredConfig Bitmap的色彩模式,不同的色彩模式,每个像素所占据的字节的数量是不一样的。
  • inSampleSize 采样率,采样率越大,Bitmap的宽和高就越小,所占用的内存也就越小。

inPreferredConfig

通过 inPreferredConfig 属性可以设置Bitmap加载的色彩模式,主要有以下几种色彩模式

  1. ALPHA_8 每个像素占据1byte
  2. ARGB_4444 每个像素占据2byte
  3. ARGB_8888 每个像素占据4byte
  4. RGB_565 每个像素占据2byte

ARGB_8888 的显式效果最好,同时也是Android默认的色彩模式,但是也最为消耗内存。

假设一张1024 x 1024,模式为ARGB_8888的图片,那么它占有的内存就是:

1024 x 1024 x 4 byte

//ARGB_8888 模式加载的Bitmap
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.wallbackground)
Log.e("TAG", "Width:${bitmap.width} Helight:${bitmap.height}")
Log.e("TAG", "Original:" + getBitmapSize(bitmap)) //Log信息如下
//Width:5040 Helight:2835
//Size:57153600 //RGB_565 这里本想使用 ARGB_4444 的测彩模式的,但是打印出来的一直却和模式的ARGB_8888相同
//可能也跟具体的设备有关系吧,所以这里就是用了 RGB_565 的色彩模式来验证一下不同的色彩模式
//占中的内存大小不同
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.RGB_565
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.wallbackground,options)
Log.e("TAG", "Width:${bitmap.width} Helight:${bitmap.height}")
Log.e("TAG", "Size:" + getBitmapSize(bitmap)) //Log信息如下
//Width:5040 Helight:2835
//Size:28576800 fun getBitmapSize(bitmap: Bitmap): Int {
return bitmap.rowBytes * bitmap.height
}

inSampleSize 采样率

采样率可以Bitmap内存优化的重头戏,上面也提到了,当使用一个大图加载到一个小图中的时候这种情况是完全不需要的,比如说 400 x 400 图片要显示在 200 x 200 的ImageView上的时候,那么只需要记载200 x 200 大小的图片就行了,而如果直接加载 400 x 400 的图片就凭白地浪费了一倍的空间。所以我们需要通过设置Bitmap的采样率将图片缩小。当然最后经过采样后的图片最好不要小于 ImageView 的大小,否则就会造成拉伸效果。

现假设要加载一个400 x 400 的图片,采样率默认是 1 也就是加载原图,如果采样变为 2 那么 图片的宽高都会 / 2 所以所占据的内存也就只有原图的 1/4(1/采样率的平方) 了。采样率越大图片的宽高越小,占用的内存也就越小。 在官方文档中推荐将采样率设置为2的N次幂(1,2,3,8..),比如说如果采样率设为 3 那么采样率就是 2 ,但是这真是一个参考,在一些机型上的运行效果并不是如此。

NOTE:

  1. 经过采样后的Bitmap的大小不应该小于 ImageView的大小。
  2. 关于采样率的计算的最终结果并不会完全地精确,会有一些上下的浮动。
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.wallbackground)
Log.e("TAG", "Size:" + getBitmapSize(bitmap))
//Log: Size:57153600 val options = BitmapFactory.Options()
options.inSampleSize = 2
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.wallbackground, options)
Log.e("TAG", "Size:" + getBitmapSize(bitmap))
//Log: 3573360 fun getBitmapSize(bitmap: Bitmap): Int {
return bitmap.rowBytes * bitmap.height
}
//Log Size:14293440

优化Bitmap加载

我想通过上面的介绍你已经大概知道了如果优化Bitmap了吧

  1. 在加载图片的时候首先获取到图片的宽和高和ImageView的宽和高(在这一步并不会加载Bitmap仅仅会获取Bitmap的宽和高)
  2. 根据图片的宽和高来和ImageView的采样率
  3. 以指定的采样率加载Bitmap

页面的布局文件如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="cn.shycoder.studybitmap.MainActivity"> <Button
android:id="@+id/btnLoadImg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Load Img" /> <ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>

Activity 的代码

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
} fun onClick(view: View) {
loadImageFromResource(iv, R.drawable.wallbackground)
} /**
* 从资源中得到一个合适大小的Bitmap
* */
private fun loadImageFromResource(imageView: ImageView, resId: Int) {
Log.e("TAG", "ImageView Width:${imageView.width} Height: ${imageView.height}") //1. 获取Bitmap的宽高
val options = BitmapFactory.Options()
// 通过设置此选项,加载Bitmap的时候,仅仅会获取宽和高并不会真正地加载Bitmap
options.inJustDecodeBounds = true
BitmapFactory.decodeResource(this.resources, resId, options) //2. 计算对应的图片的采样率
val inSampleSize = this.calculateInSampleSize(options, imageView.width, imageView.height) //3.根据采样率加载图片
//记得取消这个选项
options.inJustDecodeBounds = false
options.inSampleSize = inSampleSize
val bitmap = BitmapFactory.decodeResource(this.resources, resId, options)
imageView.setImageBitmap(bitmap)
} private fun calculateInSampleSize(options: BitmapFactory.Options, requireWidth: Int,
requireHeight: Int): Int {
val width = options.outWidth
val height = options.outHeight
var inSampleSize = 1
//如果Bitmap的大小是大于ImageView的大小的
if (width > requireWidth && height > requireHeight) {
//采样率的增加
while ((width / (inSampleSize + 1) > requireWidth)
&& (height / (inSampleSize + 1) > requireHeight)) {
inSampleSize += 1
}
} return inSampleSize
}
}

图片对比

// 原图所占内存:60466176
// 经过采样压缩后:15148960:

Android-认识Bitmap的更多相关文章

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

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

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

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

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

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

  4. android 管理Bitmap内存 - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接   Managing Bitmap Memory 管理Bitmap内存 In additi ...

  5. Android中 Bitmap Drawable Paint的获取、转换以及使用

    比如Drawable中有一系列连续的图片,img_0.png, img_1.png, img_2.png ... 如果要动态获取这些图片,通过"R.drawable.img_x"的 ...

  6. Android 图片Bitmap,drawable,res资源图片之间转换

    一.知识介绍 ①res资源图片是放在项目res文件下的资源图片 ②BitMap位图,一般文件后缀为BMP,需要编码器编码,如RGB565,RGB8888等.一种逐像素的显示对象,其执行效率高,但缺点也 ...

  7. Android中Bitmap对象和字节流之间的相互转换

    android 将图片内容解析成字节数组,将字节数组转换为ImageView可调用的Bitmap对象,图片缩放,把字节数组保存为一个文件,把Bitmap转Byte   import java.io.B ...

  8. void android.graphics.Bitmap.recycle()

    void android.graphics.Bitmap.recycle() Free up the memory associated with this bitmap's pixels, and ...

  9. android中Bitmap的放大和缩小的方法

    android中Bitmap的放大和缩小的方法 时间 2013-06-20 19:02:34  CSDN博客原文  http://blog.csdn.net/ada168855/article/det ...

  10. 关于bitmap recycle trying to use a recycled bitmap android.graphics.Bitmap

    在开发中,一直使用4.0以上手机作为測试机所以一直没有出现这个问题,今天换了2.3版本号的手机.出现了这个错误: trying to use a recycled bitmap android.gra ...

随机推荐

  1. Mybatis的分页插件PageHelper分页失效的原因

    引用博客:个人博客地址:https://alexaccele.github.io/ PageHelper是Mybatis的一个很好的分页插件,但要使用它的分页功能需要注意一下几点 1.导入相关包,例如 ...

  2. 【转】Python基础语法

    [转]Python基础语法 学习一门编程语言,通常是学习该语言的以下几个部分的内容: 基础语法:如,变量的声明与调用.基本输出语句.代码块语法.注释等: 数据类型:通常都为 数字.字符串.布尔值.数组 ...

  3. freeRTOS中文实用教程3--中断管理之中断服务例程中使用队列

    1.前言 消息队列不仅可以用于事件通信,还可以用来传递数据 2.实例说明消息队列的执行过程 3.主要API API名称 说明 参数 返回值 xQueueSendFromISR()完全等同于 xQueu ...

  4. Linux mmc framework2:基本组件之mmc

    1.前言 本文主要mmc组件的主要流程,在介绍的过程中,将详细说明和mmc相关的流程,涉及到其它组件的详细流程再在相关文章中说明. 2.主要数据结构和API TODO 3. 主要流程 3.1 mmc_ ...

  5. 测试开发之前端——No8.HTML5中的媒介事件

    媒介事件 由视频.图像以及音频等媒介触发的事件. 适用于所有 HTML 5 元素,不过在媒介元素(诸如 audio.embed.img.object 以及 video)中最常用: 属性 值 描述 on ...

  6. Ngnix日志分析

    Ngnix日志分析 cat用来读取日志内容 grep进行匹配的文本搜索 wc则进行最终的统计 grep与命令格式: grep -E “a.*b” file,ab条件同时成立 grep或命令的格式为:g ...

  7. Spring集成shiro做登陆认证

    一.背景 其实很早的时候,就在项目中有使用到shiro做登陆认证,直到今天才又想起来这茬,自己抽空搭了一个spring+springmvc+mybatis和shiro进行集成的种子项目,当然里面还有很 ...

  8. 变量 构造函数 New 关键字

    变量:脚本必须暂时地存储一些完成工作所需的信息,可以将这些数据存储在变量中.可将变量看作短暂记忆. 变量可以用来表示脚本代码中随时可能变化的值.通过使用存储在变量中的数据,可以计算出想要的结果. 声明 ...

  9. 我靠,上班eclipse看糗事百科

    package test; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; ...

  10. ERP合同审核流程处理(二十九)

    合同审批流程: 前端的代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind=" ...