*****
**图片异步加载概述**
[TOC=6]
# 1. 什么是图片的异步加载?
异步,在安卓开发中大家熟悉吗?
熟悉。
说到异步大家能想到什么呢?
多线程开发,Thread、Handler、AsyncTask。
我们在哪里使用异步呢?
网络请求数据。
图片的异步加载就是在子线线程中获取图片然后在主线程中更新到界面上的操作。
今天我们做一个需求:加载URL中的图片,显示到ImageView上。
# 2. 为什么要进行图片的二次采样?
![](https://box.kancloud.cn/a65bc06ea363c75904e84c207f733bab_240x427.jpg)
在Android应用里,最耗费内存的就是图片资源。并且在Android系统中。读取位图Bitmap时,分给虚拟机中的图片的堆栈大小仅仅有8M。假设超出了。就会出现OutOfMemory异常
~~~
E/AndroidRuntime( 697): java.lang.OutOfMemoryError
E/AndroidRuntime( 697): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
E/AndroidRuntime( 697): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:500)
E/AndroidRuntime( 697): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:353)
E/AndroidRuntime( 697): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:376)
E/AndroidRuntime( 697): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:406)
E/AndroidRuntime( 697): at com.example.imagetoshow2.ImageAdapter.createReflectedImages(ImageAdapter.java:66)
E/AndroidRuntime( 697): at com.example.imagetoshow2.ImageAdapter.getView(ImageAdapter.java:54)
E/AndroidRuntime( 697): at android.widget.AbsSpinner.onMeasure(AbsSpinner.java:193)
~~~
# 3. 了解一下关于Bitmap的Config
ARGB: A:透明度 R:红色 G:绿 B:蓝
~~~
public enum Config {
ALPHA_8 (1),
RGB_565 (3),
@Deprecated
ARGB_4444 (4),
ARGB_8888 (5);
}
~~~
Bitmap.Config ARGB\_4444:每个像素占用2byte内存 ,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
Bitmap.Config ARGB\_8888:每个像素占用4byte内存 ,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
Bitmap.Config RGB\_565:每个像素占用2byte内存,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
Bitmap.Config ALPHA\_8:每个像素占用1byte内存,只有透明度,没有颜色。
![](https://box.kancloud.cn/9a92c75f0d552dd04656ca0fadb99b28_1174x1566.png)
![](https://box.kancloud.cn/be9064158032910b55ee4fa26ba978ed_1024x1365.jpg)
# 4. 内存计算
1TB=1024GB 1GB=1024MB 1MB=1024KB 1KB=1024B 1B=8b
一张 1024 \* 1024 像素,采用ARGB8888格式,一个像素32位,每个像素就是4字节,占有内存就是4M若采用RGB565,一个像素16位,每个像素就是2字节,占有内存就是2M。
Glide加载图片默认格式RGB565,Picasso为ARGB8888,默认情况下,Glide占用内存会比Picasso低,色彩不如Picasso鲜艳,自然清晰度就低。
通常我们优化Bitmap时,当需要做性能优化或者防止OOM(Out Of Memory),我们通常会使用Bitmap.Config.RGB\_565这个配置,因为Bitmap.Config.ALPHA\_8只有透明度,显示一般图片没有意义,Bitmap.Config.ARGB\_4444显示图片不清楚,Bitmap.Config.ARGB\_8888占用内存最多。
图片加载
如果我们想要加载一张大图到内存中,如果不进行压缩的话,那么很显然就会出现OOM的崩溃,
# 5. 二次采样原理分析
如何将一张大图压缩到100kb以下并且保持不失真的特性?这就需要用到下面这个类了**BitmapFactory.Options**
BitmapFactory.Options缩放图片主要用到inSample采样率,
inSample = 1,采样后图片的宽高为原始宽高
inSample > 1,例如2,**宽高均为原图的宽高的1/2**
一个采用ARGB8888的1024 \*1024 的图片
inSample = 1,占用内存就 1024 \*1024 \*4 = 4M
inSample = 2,占用内存就 512 \*512 \* 4 = 1M
BitmapFactory 给我们提供了一个解析图片大小的参数类 BitmapFactory.Options ,把这个类的对象的 inJustDecodeBounds 参数设置为 true,这样解析出来的 Bitmap 虽然是个 null,但是 options 中可以得到图片的宽和高以及图片的类型。得到了图片实际的宽和高之后我们就可以进行压缩设置了,主要是计算图片的采样率。
`
~~~
public class BitmapUtils {
/**
* @param filePath 要加载的图片路径
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件的高度
* @return
*/
public static Bitmap getBitmap(String filePath, int destWidth, int destHeight) {
//第一次采样
BitmapFactory.Options options = new BitmapFactory.Options();
//该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点
options.inJustDecodeBounds = true;
//第一次加载图片,这时只会加载图片的边框进来,并不会加载图片中的像素点
BitmapFactory.decodeFile(filePath, options);
//获得原图的宽和高
int outWidth = options.outWidth;
int outHeight = options.outHeight;
//定义缩放比例
int sampleSize = 1;
while (outHeight / sampleSize > destHeight || outWidth / sampleSize > destWidth) {
//如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
//sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值
sampleSize *= 2;
}
/********************************************************************************************/
//至此,第一次采样已经结束,我们已经成功的计算出了sampleSize的大小
/********************************************************************************************/
//二次采样开始
//二次采样时我需要将图片加载出来显示,不能只加载图片的框架,因此inJustDecodeBounds属性要设置为false
options.inJustDecodeBounds = false;
//设置缩放比例
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
//加载图片并返回
return BitmapFactory.decodeFile(filePath, options);
}
}
~~~
`
![](https://box.kancloud.cn/3776ee2322c00dd39b896440206185a8_700x466.jpg)
跟上 学会了吗?
- 咨询项目实战
- 第一单元 HTTP协议
- 1.1 OSI七层模型
- 1.2 HTTP协议(重点)
- 1.3 HTTPS协议(了解)
- 1.4 TCP/IP协议扩展
- 1.5 WebService简介及实战(无接口)
- 1.6 课后练习
- 第二单元 HTTPURLConnection
- 2.1 ANR
- 2.2 网络判断
- 2.3 HTTPURLConnection
- 2.4 课后练习
- 第三单元 AsyncTask
- 3.1 AsyncTask概述
- 3.2 AsyncTask基本使用
- 3.3 课后练习
- 第四单元 图片异步加载
- 4.1 图片异步加载概述
- 4.2 LruCache
- 4.3 DiskLRUCache
- 4.4 图片三级缓存概述
- 4.5 封装图片加载缓存框架
- 第五单元 ListView多条目
- 5.1 ListView多条目概述
- 5.2 ListView多条目的使用
- 第六单元 ListView实现下拉刷新上拉加载
- 6.1 下拉刷新和上拉加载更多
- 6.2 XListView概述
- 6.3 XListView的使用
- 第七单元 封装网络框
- 7.1 封装网络框架概述
- 7.2 网络框架的封装
- 第八单元 项目介绍
- 8.1 公司项目团队架构简介
- 8.2 项目文档及项目流程介绍
- 8.3 项目管理
- 8.4 项目开发
- 第九单元 项目框架搭建
- 9.1 基类封装概述
- 9.2 Application中初始化配置
- 9.3 项目中的工具类
- 9.4 封装网络请求框架
- 9.5 封装图片异步缓存框架
- 第十单元 搭建UI框架1
- 10.1 侧滑菜单概述
- 10.2 主界面框架搭建
- 第十一单元 搭建UI框架2
- 11.1 TabLayout的概述
- 11.2 TabLayout的使用
- 第十二单元 图片上传
- 12.1 图片上传概述
- 12.2 图片上传的实现
- 第十三单元 PullToRefresh
- 13.1 PullToRefresh概述
- 13.2 PullToRefresh的使用
- 13.3 缓存业务实现思路
- 第十四单元 事件分发及滑动冲突
- 14.1 事件分发概述
- 14.2 事件分发流程
- 14.3 事件分发的使用
- 第十五单元 传感器的基本使用
- 15.1 传感器概述
- 15.2 传感器的使用
- 第十六单元 HTML与CSS复习
- 16.1 HTML
- 16.2 CSS
- 第十七单元 js复习
- 17.1 js基础语法
- 17.2 js数组和内置对象
- 17.3 js常用事件
- 17.4 js对象模型
- 17.5 js 正则表达式
- 第十八单元 WebView
- 18.1 WebView 概述
- 18.2 WebView的使用
- 18.3 WebView与js交互
- 第十九单元 项目案例
- 项目概述
- 第二十单元 项目答辩
- 周考
- 第一周周考
- 第二周周考
- 第三种周考
- 月考
- 接口文档