Bitmaps与优化
1、有效的处理较大的位图
图像有各种不同的形状和大小。在许多情况下,它们往往比一个典型应用程序的用户界面(UI)所需要的资源更大。
读取一个位图的尺寸和类型:
为了从多种资源来创建一个位图,BitmapFactory类提供了几个解码的方法(decodeByteArray(),decodeFile(),decodeResource()等等),根据你的图像数据资源选择最合适的解码方法。这些方法试图请求分配内存来构造位图,因此很容易导致OutOfMemory异常。每种类型的解码方式都有额外的特征可以让你通过BitMapFactory.Options类指定解码选项。当解码时避免内存分配可以设置inJustDecodeBounds属性为true,位图对象返回null但是设置了outWidth,outHeight和outMimeType。这种技术允许你在创建位图(和分配内存)之前去读取图像的尺寸和类型。
加载一个缩小版本到内存中:
现在的图像尺寸都是已知的,它们可以被用来决定是否应该加载完整的图片到内存或者是是否用一个缩小的版本去代替加载
以下是一些值得考虑的因素:
- 估计加载完整图像所需要的内存
- 你承诺家在这个图片所需空间带给你的程序的其他内存需求
- 准备加载图像的目标ImageView或UI组建的尺寸
- 当前设备的屏幕尺寸和密度
告诉解码器去重新采样这个图像,加载一个更小的版本到内存中,在你的BitmapFactory.Option对象中设置inSampleSize为true。例如,讲一个分辨率为2048*1536的图像用inSampleSize值为4去编码,将产生一个大小约为512*384的位图,加载到内存中仅使用0.75M,而不是完整的12M。这里有一个方法在目标的宽度和高度的基础上来计算一个SampleSize的值。
//计算位图的采样比例
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
//获取位图的原宽高
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
//Math.round四舍五入
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
提示:使用2的幂数设置inSampleSize的值可以使解码器更快更有效。然而,如果你想在内存或硬盘中缓存一个图片调整后的版本,通常解码到合适的图像尺寸更适合来节省空间。
要使用这种方法,首先解码,将inJustDecodeBounds设置为true,将选项传递进去,然后再次解码,再使用新的inSampleSize值并将inJustDecodeBounds设置为false:
//位图重新采样
public Bitmap decodeSampledBitmapFromResource(Resources res, int resid, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resid,options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(res, resid,options);
return bitmap;
}
示例:
public void showClick(View view) {
//显示50*50像素的图片
Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), R.drawable.ic_welcome1, 50, 50);
iv.setImageBitmap(bitmap);
}
2、缓存位图
(1)内存缓存
内存缓存提供了可以快速访问位图LruCache类用于缓存位图的任务,最近被引用的对象保存在一个被引用的LinkedHashMap中,以及在缓存超过了其指定的大小之前释放最近很少使用的对象的内存。
LRU:least recently used近期最少使用算法
public class MainActivity extends Activity {
private ImageView iv;
private LruCache<String, Bitmap> lruCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.imageView);
//获取当前Activity内存大小(基线16M,手机不同可能也不同),缓存大小基本为内存的1/8
ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
//1/8的内存大小作为缓存大小
final int cacheSize = memoryClass / 8 * 1024 * 1024;
lruCache = new LruCache<>(cacheSize);
}
//添加缓存方法
public void addBitmapToCache(String key, Bitmap bitmap) {
if (getBitmapFromCache(key) == null) {
lruCache.put(key, bitmap);
}
}
//从缓存中读取方法
public Bitmap getBitmapFromCache(String key) {
return lruCache.get(key);
}
public void showClick(View view) {
String key = String.valueOf(R.drawable.ic_welcome1);
Bitmap bitmap = getBitmapFromCache(key);
if (bitmap == null) {
//显示50*50像素的图片
bitmap = decodeSampledBitmapFromResource(getResources(), R.drawable.ic_welcome1, 50, 50);
addBitmapToCache(key, bitmap);
} else {
System.out.println("LruCache中有位图");
}
iv.setImageBitmap(bitmap);
}
//位图重新采样
public Bitmap decodeSampledBitmapFromResource(Resources res, int resid, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resid, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(res, resid, options);
return bitmap;
}
//计算位图的采样比例
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
//获取位图的原宽高
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
//Math.round四舍五入
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
}
Bitmaps与优化的更多相关文章
- Android性能优化典范
来源:http://hukai.me/android-performance-patterns/#jtss-tsina 0)Render Performance 大多数用户感知到的卡顿等性能问题的最主 ...
- Android性能优化典范第一季
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...
- [转]Android性能优化典范
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...
- [Android Pro] Android性能优化典范第一季
reference to : http://www.cnblogs.com/hanyonglu/p/4244035.html#undefined 2015年伊始,Google发布了关于Android性 ...
- Android优化—— Google 发布 Android 性能优化典范
阅读目录 0)Render Performance 1)Understanding Overdraw 2)Understanding VSYNC 3)Tool:Profile GPU Renderin ...
- [原] Android持续优化 - 提高流畅度
一.形象的感官一下流畅度概念 1. 这是官方给出的概念:Android流畅运行,需要运行60帧/秒, 则需要每帧的处理时间不超过16ms. 2. 每秒帧数,实际上就是指动画或视频每秒放映的画面数.因此 ...
- Android性能优化典范(转)
转载自oschina. 2015年伊始,Google发布了关于Android性能优化典范的专题, 一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍 ...
- Android性能优化典范(二)
Google前几天刚发布了Android性能优化典范第2季的课程,一共20个短视频,包括的内容大致有:电量优化,网络优化,Wear上如何做优化,使用对象池来提高效率,LRU Cache,Bitmap的 ...
- Redis优化经验
内存管理优化 Redis Hash是value内部为一个HashMap,如果该Map的成员数比较少,则会采用类似一维线性的紧凑格式来存储该Map, 即省去了大量指针的内存开销,这个参数控制对应在red ...
随机推荐
- Linux&C 线程控制 课后习题
Q1:多线程与多进程相比有什么优势? 多进程程序耗费的资源大,因为fork()的时候子进程需要继承父进程的几乎所有东西,但是多线程程序线程只继承一部分,即自己的私有数据,例如自己的线程ID,一组寄存器 ...
- Discovery直播 | 3D“模”术师,还原立体世界——探秘3D建模服务
通过多张普通的照片重建一个立体逼真的3D物体模型,曾经靠想象实现的事情,现在, 使用HMS Core 3D建模服务即可实现! 3D模型作为物品在数字世界中的孪生体,用户可以自己拍摄.建模并在终端直观感 ...
- Spring一套全通4—持久层整合
百知教育 - Spring系列课程 - 持久层整合 第一章.持久层整合 1.Spring框架为什么要与持久层技术进行整合 1. JavaEE开发需要持久层进行数据库的访问操作. 2. JDBC Hib ...
- Java之JNDI注入
Java之JNDI注入 About JNDI 0x01 简介 JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JND ...
- MacOS升级到Monterey后python SSL握手失败问题
MacOS升级到Monterey 12.0.1后,忽然发现原来工作正常的python3请求华为restconf API报错失败,提示 ssl.SSLError: [SSL: SSLV3_ALERT_H ...
- leakcanary内存泄漏:此篇有加了内存泄漏的apk demo
概括: ·用Android studio写一个demo ·配置leakcanary ·加入内存泄漏代码片段 ·安装apk 验证结果 ·源码地址 一.android ...
- 如何系统学习C 语言(下)之 文件篇
我们所编写的程序源代码以及编译生成的可执行文件都属于文件.所以文件的实质就是存储在外部存储介质上的一段连续的二进制数据. c 语言程序对文件的处理采用文件流的形式,程序运行在内存中,而文件是存储在外部 ...
- 问题 K: 找点
题目描述 上数学课时,老师给了LYH一些闭区间,让他取尽量少的点,使得每个闭区间内至少有一个点.但是这几天LYH太忙了,你们帮帮他吗? 输入 多组测试数据. 每组数据先输入一个N,表示有N个闭区间(N ...
- JDK的第三个LTS版本JDK17来了
目录 简介 JDK17中的新特性 语言上的新特性 核心库的优化 支持新的平台 预览特性 其他改动 总结 简介 2021年9月JDK17发布了,JDK17是最新的一个LTS版本.所谓LTS版本就是可以得 ...
- vuex基础(vuex基本结构与调用)
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const modulesA = { state:{//状态 count: ...