【Android面试】动画 & Bitmap

文章目录

  • [一、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 解码、压缩)
    复杂动画开启硬件加速
    动画结束后,及时释放动画引用,避免内存泄漏
相关推荐
愈努力俞幸运12 分钟前
function calling与mcp
android·数据库·redis
阿巴斯甜1 小时前
LeakCanary
android
MonkeyKing71551 小时前
iOS 开发 RunLoop 底层原理与应用场景
ios·面试
阿巴斯甜1 小时前
compose
android
阿巴斯甜1 小时前
Glide
android
-SOLO-1 小时前
使用Perfetto debug trace查看超时slice
android
阿巴斯甜1 小时前
Retrofit
android
阿巴斯甜2 小时前
OkHttp
android
香蕉鼠片2 小时前
面试过程中被问懵
面试·职场和发展
阿巴斯甜2 小时前
Flow
android