1.你对Bitmap了解吗?它在内存中如何存在?
Bitmap位图包括像素以及长、宽、颜色等描述信息。长宽和像素位数是用来描述图片的,可以通过这些信息可以计算图片所占内存大小。位图可以理解为一个画架,把图放在上面然后可以对图片做一系列的处理。位图文件图像显示效果好,但是非压缩格式,需要占用较大的内存空间。
Config:表示图片像素类型,包括ALPHA_8、RGB565、ARGB_4444、ARGB_8888
- ARGB_8888:4个通道都是8位,每个像素占用4个字节,图像效果最好,但占用内存较大
- ARGB_4444:4个通道都是4位,每个像素占用2个字节,图像失真较为严重
- RGB565:没有A通道,3个通道,每个像素占用2个字节,图像失真小,但是没有透明度。
- ALPHA_8:只有A通道,每个像素占用1个字节,只有透明度,没有颜色值
压缩格式CompressFormat:CompressFormat.JPEG、CompressFormat.PNG和CompressFormat.WEBP
JPEG:一种有损压缩(JPEG2000即可以有损也可以无损),文件后缀
.jpg
和.jpeg
;采用直接色,有丰富的色彩适合存储图片和生动效果图像;缺点:有损,不适合存储logo或线框图等等。PNG:一种无损压缩,文件后缀
.png
;优点:支持透明,无损,主要用于小图标,透明背景等;缺点:若色彩复杂,则图片生成后文件很大。WEBP:以WebP算法进行压缩;Google开发的新的图片格式,同时支持无损和有损压缩,使用直接色。无损压缩,相同质量的webp比PNG小大约26%;有损压缩,相同质量的webp比JPEG小25%-34% 支持动图,基本取代gif
2.有关Bitmap导致OOM的原因知道吗?如何优化?
采样压缩
1
2
3
4
5
6
7
8
9
10
11BitmapFactory.Options options = new BitmapFactory.Options();
//inJustDecodeBounds为true,不返回bitmap,只返回这个bitmap的尺寸
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), imgResId, options);
//利用返回的原图片的宽高,我们就可以计算出缩放比inSampleSize(只能是2的整数次幂)
options.inSampleSize = calculateSampleSize(options, reqWidth, reqHeight);
options.inPreferredConfig = Bitmap.Config.RGB_565;
//inJustDecodeBounds为false,返回bitmap
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),imgResId,options);1
2
3
4
5
6
7
8
9
10
11private int calculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int halfWidth = width / 2;
int halfHeight = height / 2;
int inSampleSize = 1;
if ((halfWidth / inSampleSize) >= reqWidth && (halfHeight / inSampleSize) >= reqHeight) {
inSampleSize *= 2;
}
return inSampleSize;
}缓存策略
LruCache 和 DiskLruCache
异步加载
Handler 和 线程池
3.给我谈谈图片压缩。
质量压缩
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 质量压缩
*
* @param srcBitmap 源bitmap
* @param compressFormat 图片压缩格式
* @param quality 压缩质量
* @return 返回压缩之后的bitmap
*/
public static Bitmap compressByQuality(Bitmap srcBitmap, Bitmap.CompressFormat compressFormat, int quality) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
srcBitmap.compress(Bitmap.CompressFormat.WEBP, quality, byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}采样压缩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* 采样压缩
*
* @param context 上下文
* @param resId 资源文件id
* @param reqWidth 设置的图片宽度
* @param reqHeight 设置的图片高度
* @return 返回采样后的Bitmap
*/
public static Bitmap compressBySampleSize(Context context, int resId, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
// 仅获取尺寸信息
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(context.getResources(), resId, options);
options.inSampleSize = calculateSampleSize(options, reqWidth, reqHeight);
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(context.getResources(), resId, options);
}
4.LruCache & DiskLruCache原理。
1 | public final V put(K key, V value) { |
1 | //在LruCache构造方法中通过maxsize指定最大内存,通过重写sizeOf方法指定添加的数据占用内存大小 |
5.说说你平常会使用的一些第三方图片加载库,最好给我谈谈它的原理。
6.如果让你设计一个图片加载库,你会如何设计?
缓存,压缩。
7.有一张非常大的图片,你如何去加载这张大图片?
BitmapRegionDecoder,按照区域进行加载。BitmapRegionDecoder.newInstance。