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与优化的更多相关文章

  1. Android性能优化典范

    来源:http://hukai.me/android-performance-patterns/#jtss-tsina 0)Render Performance 大多数用户感知到的卡顿等性能问题的最主 ...

  2. Android性能优化典范第一季

    2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...

  3. [转]Android性能优化典范

    2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...

  4. [Android Pro] Android性能优化典范第一季

    reference to : http://www.cnblogs.com/hanyonglu/p/4244035.html#undefined 2015年伊始,Google发布了关于Android性 ...

  5. Android优化—— Google 发布 Android 性能优化典范

    阅读目录 0)Render Performance 1)Understanding Overdraw 2)Understanding VSYNC 3)Tool:Profile GPU Renderin ...

  6. [原] Android持续优化 - 提高流畅度

    一.形象的感官一下流畅度概念 1. 这是官方给出的概念:Android流畅运行,需要运行60帧/秒, 则需要每帧的处理时间不超过16ms. 2. 每秒帧数,实际上就是指动画或视频每秒放映的画面数.因此 ...

  7. Android性能优化典范(转)

    转载自oschina. 2015年伊始,Google发布了关于Android性能优化典范的专题, 一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍 ...

  8. Android性能优化典范(二)

    Google前几天刚发布了Android性能优化典范第2季的课程,一共20个短视频,包括的内容大致有:电量优化,网络优化,Wear上如何做优化,使用对象池来提高效率,LRU Cache,Bitmap的 ...

  9. Redis优化经验

    内存管理优化 Redis Hash是value内部为一个HashMap,如果该Map的成员数比较少,则会采用类似一维线性的紧凑格式来存储该Map, 即省去了大量指针的内存开销,这个参数控制对应在red ...

随机推荐

  1. 'pybot' 不是内部或外部命令,也不是可运行的程序 或批处理文件

    在dos下运行pybot --version提示不是内部命令 这是pip list 打印信息: 解决方法: 在python/Scripts目录下加一个pybot.bat 文件 内容为: @Echo o ...

  2. vue的逆向传值(子传父)

    逆向传值:子组件传值给父组件叫做逆向传值  (是不v欸允许的,必须经过事件触发才能传值) 逆向传值步骤: 1.要传值必须先抛出,在接收 语法: this.$emit("event" ...

  3. 聊一聊声明式接口调用与Nacos的结合使用

    背景 对于公司内部的 API 接口,在引入注册中心之后,免不了会用上服务发现这个东西. 现在比较流行的接口调用方式应该是基于声明式接口的调用,它使得开发变得更加简化和快捷. .NET 在声明式接口调用 ...

  4. 2020GACTF部分wp

    GACTF misc 签到 给了二维码图 切割再拼上就行 crymisc 给了一个crymisc.docx 无法打开 用file看一下 把后缀名改成zip然后解压 这里奇怪的是用winzip解压会提示 ...

  5. 从0到1使用Kubernetes系列(七):网络

    本文是从 0 到 1 使用 Kubernetes 系列第七篇,上一篇<从 0 到 1 使用 Kubernetes 系列(六):数据持久化实战> 介绍了 Kubernetes 中的几种常用储 ...

  6. MyCat读写分离+MySql主从(一主一从)

    数据库一直在项目担当着一位核心的角色,是所有项目结构中的底层,说白了,我们程序员进行项目开发都是在和数据打交道,而数据都是保存在数据库中,如mysql.oracle.postgresql等等,如果一个 ...

  7. 纯前端实现词云展示+附微博热搜词云Demo代码

    前言 最近工作中做了几个数据可视化大屏项目,其中也有用到了词云展示,以前做词云都是用python库来生成图片显示的,这次用了纯前端的实现(Ctrl+V真好用),同时顺手做个微博热搜的词云然后记录一下~ ...

  8. 这可能是你看过最详细的NodeJS安装配置教程

    博主是一枚Java菜鸡,今天在B站上看一些教程视频的时候偶尔看了一眼评论区,发现好多人在Node和Vue安装的位置卡住了,便决定今晚肝出一套最详细的NodeJS安装配置的教程 本文适合初次接触Node ...

  9. C++getline()

    #include <iostream>#include <cstring>#include <string>using namespace std;int main ...

  10. List、ArrayList、迭代器、链表、Vector

    1.List接口中的常用方法. List是Collection接口的子接口.所以List接口中有一些特有的方法. void add(int index, Object element) Object ...