Android-认识Bitmap
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加载的色彩模式,主要有以下几种色彩模式
- ALPHA_8 每个像素占据1byte
- ARGB_4444 每个像素占据2byte
- ARGB_8888 每个像素占据4byte
- 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:
- 经过采样后的Bitmap的大小不应该小于 ImageView的大小。
- 关于采样率的计算的最终结果并不会完全地精确,会有一些上下的浮动。
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了吧
- 在加载图片的时候首先获取到图片的宽和高和ImageView的宽和高(在这一步并不会加载Bitmap仅仅会获取Bitmap的宽和高)
- 根据图片的宽和高来和ImageView的采样率
- 以指定的采样率加载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的更多相关文章
- int android.graphics.Bitmap.getRowBytes()
int android.graphics.Bitmap.getRowBytes() Return the number of bytes between rows in the bitmap's pi ...
- Android中Bitmap, Drawable, Byte,ID之间的转化
Android中Bitmap, Drawable, Byte,ID之间的转化 1. Bitmap 转化为 byte ByteArrayOutputStream out = new ByteArray ...
- Android笔记——Bitmap自动取色(纯搬运)
2015/6/12更新:发现一个更好的,带demo https://github.com/MichaelEvans/ColorArt 说明: 这个是一个老外写的自动自动从bitmap中取主色与第二主色 ...
- android 管理Bitmap内存 - 开发文档翻译
由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Managing Bitmap Memory 管理Bitmap内存 In additi ...
- Android中 Bitmap Drawable Paint的获取、转换以及使用
比如Drawable中有一系列连续的图片,img_0.png, img_1.png, img_2.png ... 如果要动态获取这些图片,通过"R.drawable.img_x"的 ...
- Android 图片Bitmap,drawable,res资源图片之间转换
一.知识介绍 ①res资源图片是放在项目res文件下的资源图片 ②BitMap位图,一般文件后缀为BMP,需要编码器编码,如RGB565,RGB8888等.一种逐像素的显示对象,其执行效率高,但缺点也 ...
- Android中Bitmap对象和字节流之间的相互转换
android 将图片内容解析成字节数组,将字节数组转换为ImageView可调用的Bitmap对象,图片缩放,把字节数组保存为一个文件,把Bitmap转Byte import java.io.B ...
- void android.graphics.Bitmap.recycle()
void android.graphics.Bitmap.recycle() Free up the memory associated with this bitmap's pixels, and ...
- android中Bitmap的放大和缩小的方法
android中Bitmap的放大和缩小的方法 时间 2013-06-20 19:02:34 CSDN博客原文 http://blog.csdn.net/ada168855/article/det ...
- 关于bitmap recycle trying to use a recycled bitmap android.graphics.Bitmap
在开发中,一直使用4.0以上手机作为測试机所以一直没有出现这个问题,今天换了2.3版本号的手机.出现了这个错误: trying to use a recycled bitmap android.gra ...
随机推荐
- js获取对象的最后一个
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-i ...
- MySQL基于LVM快照的备份恢复(临时)
目录1.数据库全备份2.准备LVM卷3.数据恢复到LVM卷4.基于LVM快照备份数据5.数据灾难恢复6.总结 写在前面:测试环境中已安装有mysql 5.5.36数据库,但数据目录没有存放在LVM卷, ...
- Linux内核驱动之GPIO子系统(一)GPIO的使用【转】
转自:http://blog.csdn.net/tommy_wxie/article/details/9427047 一 概述 Linux内核中gpio是最简单,最常用的资源(和 interrupt ...
- Linux版本Membase无法写入default bucket的问题分析
最近项目中使用的membase发现出了点问题,生产环境中读写各种数据都正常,可是新搭建的开发环境下,只有default bucket写不进去数据,调用store总是返回FALSE,配置文件也是一模一样 ...
- windows 7安装apache
最近想在PHPEclipse 上开发PHP项目,但遇到的一个问题是:无法在Web 上浏览PHP页面,更谈不上调试了.这一点让人很是纠结,在浏览网上大量的相关内容后,该问题已经解决. 具体的操作过程详见 ...
- [学习笔记]Java的public,protected,private,缺省的作用域
0.引言 Java的访问指示符public,protected,private,缺省可以用来修饰类和方法. 1.作用域如下 具体如下: 作用域 当前类 同一package 子孙类 ...
- SonarQube代码质量管理工具的升级(sonarqube6.2 + sonar-scanner-2.8 + MySQL5.6+)
SonarQube升级注意事项 0. 前提条件 如果之前是使用sonarqube5.2 + sonar-runner-2.4 +MySQL5.5版本或者类似的组合. 安装方法请参照SonarQube代 ...
- viewpager显示图片的Adapter
package com.ming.chiye.yishanghorse.Adapter; import android.content.Context; import android.graphics ...
- IOS支持多国语言
- SpringMVC(3):DispatcherServlet详解
原文出处: 张开涛 3.1.DispatcherServlet作用 DispatcherServlet是前端控制器设计模式的实现,提供spring Web MVC的集中访问点,而且负责职责的分派,而且 ...