01.图片基础概念介绍
1.1 图片占用内存介绍
移动设备的系统资源有限,所以应用应该尽可能的降低内存的使用。
在应用运行过程中,Bitmap (图片)往往是内存占用最大的一个部分,Bitmap 图片的加载和处理,通常会占用大量的内存空间,所以在操作 Bitmap 时,应该尽可能的小心。
Bitmap 会消耗很多的内存,特别是诸如照片等内容丰富的大图。
例如,一个手机拍摄的 2700 * 1900 像素的照片,需要 5.1M 的存储空间,但是在图像解码配置 ARGB_8888 时,它加载到内存需要 19.6M 内存空间(2592 * 1936 * 4 bytes),从而迅速消耗掉该应用的剩余内存空间。
OOM 的问题也是我们常见的严重问题,OOM 的产生的一个主要场景就是在大图片分配内存的时候产生的,如果 APP 可用内存紧张,这时加载了一张大图,内存空间不足以分配该图片所需要的内存,就会产生 OOM,所以控制图片的高效使用是必备技能。
1.2 加载网络图片流程
这一部分压缩和缓存图片,在glide源码分析的文章里已经做出了比较详细的说明。在这里简单说一下图片请求加载过程……
在使用App的时候,会经常需要加载一些网络图片,一般的操作步骤大概是这样的:
第一步从网络加载图片:一般都是通过网络拉取的方式去服务器端获取到图片的文件流后,再通过BitmapFactory.decodeStream(InputStream)来加载图片Bitmap。
第二步这种压缩图片:网络加载图片方式加载一两张图片倒不会出现问题,但是如果短时间内加载十几张或者几十张图片的时候,就很有可能会造成OOM(内存溢出),因为现在的图片资源大小都是非常大的,所以我们在加载图片之前还需要进行相应的图片压缩处理。
第三步变换图片:比如需要裁剪,切割圆角,旋转,添加高斯模糊等属性。
第四步缓存图片:但又有个问题来了,在使用移动数据的情况下,如果用户每次进入App的时候都会去进行网络拉取图片,这样就会非常的浪费数据流量,这时又需要对图片资源进行一些相应的内存缓存以及磁盘缓存处理,这样不仅节省用户的数据流量,还能加快图片的加载速度。
第五步异步加载:虽然利用缓存的方式可以加快图片的加载速度,但当需要加载很多张图片的时候(例如图片墙瀑布流效果),就还需用到多线程来加载图片,使用多线程就会涉及到线程同步加载与异步加载问题。
1.3 三方库加载图片逻辑
先说出结论,目前市面较为常用的大概是Glide,Picasso,Fresco等。大概的处理图片涉及主要逻辑有:
从网络或者本地等路径拉取图片;然后解码图片;然后进行压缩;接着会有图片常用圆角,模糊或者裁剪等处理;然后三级缓存加载的图片;当然加载图片过程涉及同步加载和异步加载;最后设置到具体view控件上。
1.4 从网络直接拉取图片
直接通过网络请求将网络图片转化成bitmap
在这将采用最原生的网络请求方式HttpURLConnection方式进行图片获取。
经过测试,请求8张图片,耗时毫秒值174。一般是通过get请求拉取图片的。这种方法应该是最基础的网络请求,大家也可以回顾一下,一般开发中很少用这种方式加载图片。具体可以看:ImageToolLib
如何加载一个图片呢?
可以看看BitmapFactory类为我们提供了四类方法来加载Bitmap:decodeFile、decodeResource、decodeStream、decodeByteArray;也就是说Bitmap,Drawable,InputStream,Byte[] 之间是可以进行转换。
1.5 加载图片的流程
搞清楚一个图片概念
在电脑上看到的 png 格式或者 jpg 格式的图片,png(jpg) 只是这张图片的容器。是经过相对应的压缩算法将原图每个像素点信息转换用另一种数据格式表示。
加载图片显示到手机
通过代码,将这张图片加载进内存时,会先解析(也就是解码操作)图片文件本身的数据格式,然后还原为位图,也就是 Bitmap 对象。
图片大小vs图片内存大小
一张 png 或者 jpg 格式的图片大小,跟这张图片加载进内存所占用的大小完全是两回事。
1.6 Bitmap能直接存储吗
Bitmap基础概念
Bitmap对象本质是一张图片的内容在手机内存中的表达形式。它将图片的内容看做是由存储数据的有限个像素点组成;每个像素点存储该像素点位置的ARGB值。每个像素点的ARGB值确定下来,这张图片的内容就相应地确定下来了。
Bitmap本质上不能直接存储
为什么?bitmap是一个对象,如果要存储成本地可以查看的图片文件,则必须对bitmap进行编码,然后通过io流写到本地file文件上。
1.7 Bitmap创建流程
对于图片OOM,可以发现一个现象。
heapsize(虚拟机的内存配置)越大越不容易 OOM,Android8.0 及之后的版本更不容易 OOM,这个该如何理解呢?
Bitmap对象内存的变化:
在 Android 8.0 之前,Bitmap 像素占用的内存是在 Java heap 中分配的;8.0 及之后,Bitmap 像素占用的内存分配到了 Native Heap。
由于 Native heap 的内存分配上限很大,32 位应用的可用内存在 3~4G,64 位上更大,虚拟内存几乎很难耗尽,所以推测 OOM 时 Java heap 中占用内存较多的对象是 Bitmap” 成立的情况下,应用更不容易 OOM。
搞清楚Bitmap对象内存分配
Bitmap 的构造方法是不公开的,在使用 Bitmap 的时候,一般都是通过 Bitmap、BitmapFactory 提供的静态方法来创建 Bitmap 实例。
以 Bitmap.createBitmap 说明了 Bitmap 对象的主要创建过程分析,可以看到 Java Bitmap 对象是在 Native 层通过 NewObject 创建的。
allocateJavaPixelRef,是 8.0 之前版本为 Bitmap 像素从 Java heap 申请内存。其核心原理是Bitmap 的像素是保存在 Java 堆上。
allocateHeapBitmap,是 8.0 版本为 Bitmap 像素从 Native heap 申请内存。其核心原理主要是通过 calloc 为 Bitmap 的像素分配内存,这个分配就在 Native 堆上。
更多详细内容可以看:Bitmap对象内存分配
1.8 图片框架如何设计
大多数图片框架加载流程
概括来说,图片加载包含封装,解析,下载,解码,变换,缓存,显示等操作。
图片框架是如何设计的
封装参数:从指定来源,到输出结果,中间可能经历很多流程,所以第一件事就是封装参数,这些参数会贯穿整个过程;
解析路径:图片的来源有多种,格式也不尽相同,需要规范化;比如glide可以加载file,io,id,网络等各种图片资源
读取缓存:为了减少计算,通常都会做缓存;同样的请求,从缓存中取图片(Bitmap)即可;
查找文件/下载文件:如果是本地的文件,直接解码即可;如果是网络图片,需要先下载;比如glide这块是发起一个请求
解码:这一步是整个过程中最复杂的步骤之一,有不少细节;比如glide中解析图片数据源,旋转方向,图片头等信息
变换和压缩:解码出Bitmap之后,可能还需要做一些变换处理(圆角,滤镜等),还要做图片压缩;
缓存:得到最终bitmap之后,可以缓存起来,以便下次请求时直接取结果;比如glide用到三级缓存
显示:显示结果,可能需要做些动画(淡入动画,crossFade等);比如glide设置显示的时候可以添加动画效果
02.图片内存计算方式
2.1 如何计算占用内存
如果图片要显示下Android设备上,ImageView
Android Bitmap使用demo
需积分: 0 110 浏览量
更新于2023-05-04
收藏 12.85MB ZIP 举报
在Android开发中,Bitmap是用于表示图像数据的基本类,它在UI设计和图像处理中扮演着重要角色。本文将深入探讨Bitmap的使用,包括如何创建和编辑Bitmap,以及如何调整Bitmap的明度、亮度和RGB色相。
让我们了解Bitmap的创建方式。在Android中,Bitmap可以通过几种不同的途径来创建:
1. **从资源加载**: 可以使用`BitmapFactory`类的方法如`decodeResource()`从XML资源文件加载Bitmap。
```java
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
```
2. **从文件加载**: 使用`decodeFile()`方法加载本地文件系统的图片。
```java
File file = new File("/path/to/image.jpg");
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
```
3. **从流加载**: 对于网络图片或内存中的字节流,可以使用`decodeStream()`方法。
```java
InputStream is = ...; // 获取输入流
bitmap = BitmapFactory.decodeStream(is);
```
4. **直接创建**: 使用`Bitmap.createBitmap()`方法指定宽度、高度和颜色格式创建空的Bitmap。
```java
int width = 100;
int height = 200;
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
```
接下来,我们讨论Bitmap的编辑。Android提供了多种方法来修改Bitmap的内容:
1. **绘图**:使用`Canvas`对象可以在Bitmap上进行绘图操作,比如画线、矩形、圆形等,也可以绘制其他Bitmap或View。
```java
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
canvas.drawCircle(50, 50, 30, paint);
```
2. **颜色调整**:可以使用`ColorMatrix`对Bitmap的颜色进行操作,比如改变亮度、对比度、饱和度等。以下代码用于调整亮度:
```java
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.set(new float[]{
1, 0, 0, 0, brightness, // Brightness adjustment
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0});
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
```
3. **色相调整**:对于RGB色相调整,通常需要使用像素级别的操作,通过获取每个像素的RGB值,然后根据HSL色彩空间进行转换并重新设置。这种方法比较复杂,一般不直接提供API,但可以借助第三方库如`androidx.palette.graphics.Palette`来分析Bitmap的色彩。
4. **滤镜效果**:Android支持多种滤镜效果,如模糊、灰度、锐化等,这些可以通过`RenderScript`或自定义`Shader`实现。
在实际应用中,需要注意Bitmap的内存管理。由于Bitmap占用大量内存,不恰当的使用可能导致内存溢出。因此,使用完毕后应调用`recycle()`释放资源,或者使用`BitmapFactory.Options`的`inBitmap`参数复用已有的Bitmap内存。
`BitmapDemo`这个项目可能包含了上述概念的示例代码,可以作为学习和实践Bitmap操作的起点。通过这个项目,你可以更深入地理解Bitmap的使用,并能够创建和编辑Bitmap,调整其色彩属性,以满足各种UI需求。
Android的Bitmap类提供了强大的图像处理能力,开发者可以灵活地创建、编辑和调整图像,从而实现丰富的视觉效果。在实际开发中,结合适当的内存管理策略,Bitmap可以成为构建优美用户体验的重要工具。

12345,catchatiger
- 粉丝: 312