文章目录
- [一、Bitmap 基础与内存](#一、Bitmap 基础与内存)
-
- [1. BitmapFactory 加载 Bitmap 的常用方法有哪些?各自适用场景?](#1. BitmapFactory 加载 Bitmap 的常用方法有哪些?各自适用场景?)
- [2. Bitmap 的复用机制(inBitmap)是什么?如何实现?](#2. Bitmap 的复用机制(inBitmap)是什么?如何实现?)
- [3. 安卓中 Bitmap 内存占用如何计算?大图加载 OOM 如何避免,给出完整实战方案。](#3. 安卓中 Bitmap 内存占用如何计算?大图加载 OOM 如何避免,给出完整实战方案。)
- [4. Glide/Picasso 加载 Bitmap 的内存缓存、磁盘缓存原理,及 Bitmap 复用(inBitmap)的使用场景与限制](#4. Glide/Picasso 加载 Bitmap 的内存缓存、磁盘缓存原理,及 Bitmap 复用(inBitmap)的使用场景与限制)
- [5. 大图长图(如长海报、地图)如何实现高效加载与显示,避免卡顿与 OOM。](#5. 大图长图(如长海报、地图)如何实现高效加载与显示,避免卡顿与 OOM。)
- [6. Bitmap 在不同安卓版本(8.0 前后)的内存分配变化,及对应适配方案。](#6. Bitmap 在不同安卓版本(8.0 前后)的内存分配变化,及对应适配方案。)
- [二、Bitmap 绘制与性能(实战应用)](#二、Bitmap 绘制与性能(实战应用))
-
- [1. Canvas 绘制 Bitmap 时,如何避免过度绘制、提升绘制效率?](#1. Canvas 绘制 Bitmap 时,如何避免过度绘制、提升绘制效率?)
- [2. 图片圆角、圆形、阴影的实现方式,哪种性能最优?实战中如何选择。](#2. 图片圆角、圆形、阴影的实现方式,哪种性能最优?实战中如何选择。)
- 三、动画基础
-
- [1. 常见动画分类](#1. 常见动画分类)
- [2. 属性动画的核心原理是什么?与视图动画的本质区别?](#2. 属性动画的核心原理是什么?与视图动画的本质区别?)
- [3. 属性动画内存泄漏原因(如持有 View 引用),实战中如何避免。](#3. 属性动画内存泄漏原因(如持有 View 引用),实战中如何避免。)
- [4. ValueAnmimator与objectAnimator的应用场景](#4. ValueAnmimator与objectAnimator的应用场景)
- [四. 综合实战题](#四. 综合实战题)
-
- [1. 实现一个图片加载 + 渐显动画 + 滑动销毁的组件,需兼顾 Bitmap 内存、动画性能、用户体验。](#1. 实现一个图片加载 + 渐显动画 + 滑动销毁的组件,需兼顾 Bitmap 内存、动画性能、用户体验。)
- [2. 列表(RecyclerView)中图片加载与动画(如入场、刷新)的性能优化,避免卡顿与闪烁。](#2. 列表(RecyclerView)中图片加载与动画(如入场、刷新)的性能优化,避免卡顿与闪烁。)
- [3. 自定义 View 中 Bitmap 绘制 + 属性动画结合的实战,如何保证流畅度(60fps)。](#3. 自定义 View 中 Bitmap 绘制 + 属性动画结合的实战,如何保证流畅度(60fps)。)
- [4. 结合 Bitmap 与属性动画,实现一个 "图片渐变放大显示" 的实战效果,需注意内存优化。](#4. 结合 Bitmap 与属性动画,实现一个 “图片渐变放大显示” 的实战效果,需注意内存优化。)
- [5. 如何避免 Bitmap 与动画结合使用时的卡顿与 OOM?](#5. 如何避免 Bitmap 与动画结合使用时的卡顿与 OOM?)
一、Bitmap 基础与内存
1. BitmapFactory 加载 Bitmap 的常用方法有哪些?各自适用场景?
- decodeFile(String pathName):从本地文件路径加载,适用于本地相册、下载的图片文件。
- decodeResource(Resources res, int id):从应用资源文件(res/drawable等)加载,适用于应用内置图片。
- decodeStream(InputStream is):从输入流加载,适用于网络图片、资产文件(assets)、内容提供者(ContentProvider)获取的图片。
- decodeByteArray(byte[] data, int offset, int length):从字节数组加载,适用于图片数据已读取到内存、需快速解析的场景。
- 核心注意:加载大图片时,需配合 BitmapFactory.Options 进行采样压缩,避免 OOM。
2. Bitmap 的复用机制(inBitmap)是什么?如何实现?
- 概念:
通过复用已分配的 Bitmap 内存空间,避免重复申请内存,减少内存碎片和 GC 频率,提升加载效率。 - 实现规则:
Android 版本限制:
4.4(API 19)及以上:新 Bitmap 的内存大小 ≤ 旧 Bitmap 内存大小,即可复用;
4.4 以下:新 Bitmap 与旧 Bitmap 的宽高、像素格式必须完全一致,才能复用。
配置要求:设置 BitmapFactory.Options 的 inBitmap 属性,赋值为已存在的可复用 Bitmap。
注意事项:复用前需确认旧 Bitmap 未被引用、已释放;复用后旧 Bitmap 不可再使用,避免内存错乱。
3. 安卓中 Bitmap 内存占用如何计算?大图加载 OOM 如何避免,给出完整实战方案。
- 内存计算公式:内存大小 = 宽 × 高 × 每个像素占用字节数
- OOM 完整实战方案:
- 降采样(inSampleSize):按屏幕尺寸计算合适比例,避免加载原图
- 格式优化:无透明场景使用 RGB_565,内存直接减半
- Bitmap 复用(inBitmap):复用旧 Bitmap 内存,避免频繁 GC
- LruCache 内存缓存 + 弱引用池:控制缓存上限
- 大图分片加载:BitmapRegionDecoder 只加载可视区域
- 及时回收:不用的 Bitmap 调用 recycle ()(8.0 以下必须)
4. Glide/Picasso 加载 Bitmap 的内存缓存、磁盘缓存原理,及 Bitmap 复用(inBitmap)的使用场景与限制
- 缓存原理:
内存缓存:LruCache(强引用)+ 弱引用池(用于复用)
磁盘缓存:缓存原始图、裁剪图、转换图 - inBitmap 复用:
4.4+:新 Bitmap 内存 ≤ 旧 Bitmap 即可复用
4.4 以下:宽高、格式必须完全一致
5. 大图长图(如长海报、地图)如何实现高效加载与显示,避免卡顿与 OOM。
- 使用 BitmapRegionDecoder 分片加载
- 监听滑动,动态加载当前可视区域
- 配合 inBitmap 复用 + LruCache 缓存
- 避免一次性加载全图
6. Bitmap 在不同安卓版本(8.0 前后)的内存分配变化,及对应适配方案。
- 8.0 前:Bitmap 内存在 Native 堆 → 必须手动 recycle ()
- 8.0 后:Bitmap 内存在 Java 堆 → GC 自动管理
- 适配:8.0 以下必须 recycle;8.0 以上建议主动释放。
二、Bitmap 绘制与性能(实战应用)
1. Canvas 绘制 Bitmap 时,如何避免过度绘制、提升绘制效率?
- onDraw 中禁止创建 Bitmap/Canvas
- 使用 clipRect 限制绘制区域,减少过度绘制
- 简单绘制开启硬件加速;复杂绘制关闭
- 使用矩阵变换代替多次裁剪
2. 图片圆角、圆形、阴影的实现方式,哪种性能最优?实战中如何选择。
-
使用 ViewOutlineProvider(推荐首选)
适用版本:Android 5.0(API 21)及以上
优点:由系统支持,GPU 渲染,性能最优,适合实现圆形或统一圆角
缺点:不支持阴影,不能设置不同半径的圆角
使用方式:通过 setOutlineProvider() 设置圆形或圆角轮廓
-
使用图片加载库(如 Glide)的 Transformation
优点:集成方便,适合网络图片加载时统一处理
缺点:每次加载都要处理图片,可能增加内存开销
使用方式:Glide.with(context).load(url).transform(new RoundedCorners(16))、
-
使用 Canvas.drawRoundRect() + Paint.setShadowLayer()
优点:支持阴影,适合自定义绘制
缺点:性能一般,绘制复杂时可能影响帧率
使用场景:需要阴影或更复杂的 UI 效果时使用
-
使用 CardView 包裹 ImageView
优点:简单易用,支持圆角和阴影
缺点:性能一般,阴影渲染有一定开销
使用方式:设置 cardCornerRadius 和 elevation
-
使用第三方库(如 RoundedImageView、GPUImage)
优点:功能强大,兼容性好
缺点:引入额外依赖,可能增加 APK 体积
三、动画基础
1. 常见动画分类

2. 属性动画的核心原理是什么?与视图动画的本质区别?
- 核心原理:
属性动画通过 ValueAnimator 监听动画进度,计算目标属性的中间值,通过 反射 调用对象的 setXXX 方法修改真实属性;ObjectAnimator 封装了 ValueAnimator,自动反射调用 setXXX,更简洁。 - 本质区别:
视图动画 :仅修改 View 的绘制层,不改变 View 的布局参数(如 left、top、width),点击事件仍在原位置 ;
属性动画 :直接修改 View 的真实布局属性和成员变量,View 的位置、大小等实际属性发生变化,点击事件同步更新。
3. 属性动画内存泄漏原因(如持有 View 引用),实战中如何避免。
- 泄漏原因:动画持有 View 强引用,View 销毁但动画未停
- 避免:
onDestroy/onDetached 取消动画
使用弱引用
避免无限循环动画
4. ValueAnmimator与objectAnimator的应用场景
- ValueAnimator 常见使用场景:
自定义 View 动画(如圆形进度条、路径动画)
颜色渐变动画(结合 ArgbEvaluator)
数值型动画(如计数器动画、进度更新)
动态 UI 更新(如动态绘制、Canvas 动画)
- ObjectAnimator 常见使用场景:
View 属性动画(如 translationX, alpha, rotation)
组合动画(配合 AnimatorSet 实现动画顺序控制)
点击反馈动画(如按钮点击缩放、Material 风格动画)
页面转场动画(Fragment/Activity 切换动画)
RecyclerView Item 动画(进入/点击动画)
如果是简单的 View 动画,推荐使用 ObjectAnimator,开发效率高
如果是自定义控件动画或复杂逻辑,推荐使用 ValueAnimator,更灵活可控。
四. 综合实战题
1. 实现一个图片加载 + 渐显动画 + 滑动销毁的组件,需兼顾 Bitmap 内存、动画性能、用户体验。
- 图片加载:Glide 加载 + RGB_565 + inBitmap
- 渐显动画:ObjectAnimator 控制 alpha
- 滑动销毁:GestureDetector + 属性动画平移 + 边界回弹
- 内存:及时释放、复用、缓存控制
2. 列表(RecyclerView)中图片加载与动画(如入场、刷新)的性能优化,避免卡顿与闪烁。
- 图片:Glide 预加载、复用、降采样
- 动画:使用 ItemAnimator,避免频繁 invalidate
- 防闪烁:固定尺寸、关闭默认动画、使用 holder 缓存
3. 自定义 View 中 Bitmap 绘制 + 属性动画结合的实战,如何保证流畅度(60fps)。
- Bitmap 预创建、复用
- onDraw 无对象创建
- 属性动画使用硬件加速
- 减少绘制区域、避免过度绘制
- 控制 invalidate 频率
4. 结合 Bitmap 与属性动画,实现一个 "图片渐变放大显示" 的实战效果,需注意内存优化。
- Bitmap 加载优化:
使用 BitmapFactory.Options 计算采样率 ,按 ImageView 尺寸压缩图片;
优先使用 RGB_565 格式 (无透明需求时),减少内存占用;
加载完成后,及时回收原始资源,避免内存泄漏。 - 动画实现:
初始状态:设置 ImageView 的 alpha 为 0,scaleX/scaleY 为 0.5;
属性动画组合 :使用 AnimatorSet 同时执行 AlphaAnimation(alpha 从 0→1)和 ScaleAnimation(scaleX/scaleY 从 0.5→1),时长 500ms,插值器使用 AccelerateDecelerateInterpolator(加速减速);
动画监听:动画结束后,若不再使用 Bitmap,调用 bitmap.recycle () 释放内存,配合 System.gc () 触发 GC。 - 内存防护:
避免在 onDraw 中创建 Bitmap ;
列表场景中,使用 Glide/Picasso 结合 Bitmap 复用池,复用 Bitmap 内存。
5. 如何避免 Bitmap 与动画结合使用时的卡顿与 OOM?
- 内存优化:
强制采样压缩 :所有 Bitmap 加载前必须计算 inSampleSize,禁止加载原图;
合理选择格式 :无透明图用 RGB_565,内存减半;
及时回收 :Activity/Fragment 销毁时,调用 Bitmap.recycle (),并置为 null;
复用池:集成 LruCache 缓存常用 Bitmap,配合 inBitmap 复用内存。 - 动画性能优化:
避免在动画更新中执行耗时操 作(如 Bitmap 解码、压缩)
复杂动画开启硬件加速
动画结束后,及时释放动画引用,避免内存泄漏