【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 解码、压缩)
    复杂动画开启硬件加速
    动画结束后,及时释放动画引用,避免内存泄漏
相关推荐
网域小星球2 小时前
C++ 从 0 入门(五)|C++ 面试必知:静态成员、友元、const 成员(高频考点)
开发语言·c++·面试·静态成员·友元函数
黑牛儿2 小时前
面试高频问题:从浏览器请求到PHP响应:完整流程拆解
android·后端·面试·php
中小企业实战军师刘孙亮2 小时前
先锁定目标客户,再找获客方法-佛山鼎策创局破局增长咨询
职场和发展·产品运营·创业创新·需求分析·学习方法
嘻嘻哈哈樱桃3 小时前
数据流中的中位数 力扣--160
算法·leetcode·职场和发展
M ? A3 小时前
你的 Vue v-for,VuReact 会编译成什么样的 React 代码?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
2501_933670793 小时前
大厂HR内部爆料:2026年招聘资深员工,拥有这些证书的简历优先进入面试池!
面试·职场和发展
逻辑驱动的ken3 小时前
Java高频面试场景题07
java·开发语言·面试·职场和发展·求职招聘·春招
callJJ3 小时前
JVM 内存区域划分详解——从生活比喻到运行时数据区全景图
java·jvm·面试·内存区域划分
y小花3 小时前
安卓USB服务概述
android·usb