2026小知识点-简(7)

7 阅读11分钟

1、Glide简介:

性维度Glide 的核心实现与优势关键面试解读
图片解码与内存默认解码格式为 RGB_565,内存占用约为ARGB_8888的一半;支持智能的 Bitmap 池复用取舍思维:以轻微的色彩损失换取大幅内存节省,适合图片海量的App。
生命周期集成通过注入一个无UI的 Fragment 监听 Activity/Fragment 生命周期,实现请求的自动暂停、恢复和销毁架构设计思想:将生命周期管理内化,对开发者透明,是防止内存泄漏的关键。
缓存策略四级缓存:活动资源、内存、磁盘资源(缓存的)、磁盘文件(数据)。其中活动资源缓存是独到设计。性能优化精髓:活动资源缓存直接引用正在使用的图片,避免频繁回收导致的卡顿。
加载流程统一的 ModelLoader 注册机制,支持多种数据源(URL、File、ContentProvider等)无缝扩展。设计模式应用:典型的责任链模式,体现了高度的可扩展性和模块化设计。

2、高效的四级缓存机制

缓存流程活动资源 -> 内存缓存 -> 磁盘资源 -> 磁盘文件 -> 网络/源加载

  1. 活动资源缓存:一个 WeakReferenceHashMap,持有当前正在展示的图片引用。这是为了避免同一图片在列表快速滚动时被重复加载和回收,直接解决界面卡顿。
  2. 内存缓存:一个 LruCache,存储最近加载过的图片,采用 LRU 算法管理。
  3. 磁盘资源缓存:存储经过解码、转换后的图片。
  4. 磁盘文件缓存:存储原始的图片数据(如网络下载的原始文件)。

3、 高效的Bitmap管理与复用

Bitmap池:Glide维护了一个 BitmapPool(通常是 LruBitmapPool)。当 Bitmap 从内存缓存中被移除或 ImageView 被复用时,其 Bitmap 对象不会直接被回收,而是放入 BitmapPool。当需要加载一张新图片时,Glide会尝试从 BitmapPool 中找一个可复用的 Bitmap 对象,直接复用其内存,从而避免频繁的 Bitmap 内存分配与回收,减少GC停顿和内存抖动

4、Glide的加载流程是怎样的?

参考答案:从Glide.with().load().into()开始,主要流程包括:

  • 请求构建:创建RequestBuilder,封装图片URL、尺寸、变换等参数
  • 缓存检查:依次检查活动资源缓存(弱引用)、内存缓存(LruCache)、磁盘缓存
  • 数据获取:若缓存未命中,通过ModelLoader获取数据源(网络、文件、资源等)
  • 解码转换:在后台线程通过DecodeJob进行图片解码、采样、变换处理
  • 显示结果:回到主线程通过Target将Bitmap设置到ImageView
  • 缓存存储:将处理后的图片存入内存缓存和磁盘缓存

5、Glide如何保证不内存泄漏?

  • A: 通过向宿主 Activity/Fragment 添加一个无UI的 Fragment,利用其生命周期回调,在页面销毁时自动取消所有未完成的请求并清理资源。这是其设计的核心安全机制。

6、Glide和Picasso在加载同一张图片到相同大小的ImageView时,内存占用可能不同,为什么?

  • A: 关键在于默认的 Bitmap 配置不同。Picasso默认使用 ARGB_8888,每个像素占4字节。而Glide默认使用 RGB_565,每个像素占2字节。因此,在相同分辨率下,Glide加载的图片内存占用约为Picasso的一半。当然,Glide可以通过 .format() 方法更改配置。

7、如何配置磁盘缓存策略?

参考答案:通过DiskCacheStrategy配置:

  • ALL:缓存原始数据和转换后数据
  • NONE:不缓存任何数据
  • DATA:只缓存原始数据
  • RESOURCE:只缓存转换后数据
  • AUTOMATIC:根据数据源智能选择(默认策略)

8、如何优化Glide加载性能?

参考答案

  • 尺寸优化:使用override(width, height)指定精确尺寸,避免加载过大图片
  • 缓存策略:根据业务场景选择合适的DiskCacheStrategy
  • 预加载:对即将显示的图片使用preload()提前加载到缓存
  • 列表优化:在RecyclerView快速滑动时使用pauseRequests()暂停加载
  • 采样率优化:Glide会自动根据ImageView尺寸计算inSampleSize,减少内存占用

9、Glide如何防止OOM?

参考答案

  • 自动采样:根据ImageView的宽高和图片原始尺寸,自动计算合适的inSampleSize进行采样
  • 尺寸适配:通过override()指定目标尺寸,避免加载过大的Bitmap
  • 内存缓存控制:使用LruCache限制内存缓存大小,超出时自动回收
  • 弱引用管理:活动资源缓存使用弱引用,当内存紧张时会被GC回收
  • Bitmap复用:在Android 4.4+使用BitmapPool复用Bitmap内存

10、常用的图片变换有哪些?如何实现圆角图片?

参考答案

  • 内置变换CenterCrop(居中裁剪)、FitCenter(居中缩放)、CircleCrop(圆形裁剪)
  • 圆角实现
Glide.with(context)
    .load(url)
    .transform(RoundedCorners(radius)) // 使用内置圆角变换
    .into(imageView)

11、Glide支持哪些图片格式?

参考答案:支持JPEG、PNG、GIF、WebP等常见格式,通过不同的Decoder进行解码。对于GIF,需要使用asGif()明确指定格式。

12、加载失败如何处理?

参考答案

  • 占位图设置:使用placeholder()设置加载中占位图,error()设置加载失败占位图
  • 监听回调:通过listener()添加RequestListener,在onLoadFailed()中处理失败逻辑
  • 重试机制:可自定义ModelLoader实现重试逻辑

13、Glide与Picasso、Fresco的对比

参考答案(从几个维度对比):

  • 功能特性:Glide功能最全面(支持GIF、视频帧等),Picasso轻量,Fresco专攻大图
  • 内存占用:Glide通过BitmapPool优化内存,Picasso较简单,Fresco使用Native内存
  • 缓存机制:Glide三级缓存最完善,Picasso两级缓存,Fresco使用Native缓存
  • API设计:Glide链式调用灵活,Picasso简洁,Fresco配置复杂
  • 适用场景:Glide适合大多数场景,Picasso适合简单需求,Fresco适合大图加载

14、列表快速滑动时如何优化?

参考答案

  • 在RecyclerView的onScrollStateChanged()中监听滑动状态
  • 当快速滑动时调用Glide.with(context).pauseRequests()暂停加载
  • 滑动停止时调用resumeRequests()恢复加载
  • 避免在快速滑动时加载大量图片导致卡顿

15、使用Glide怎么加载大图片

加载大图片时,确实需要特别注意内存优化和显示效果。下面这个表格汇总了核心方法和关键配置,方便你快速把握要点。

优化维度核心方法/配置作用说明
📏 尺寸控制override(width, height)指定精确的加载尺寸,避免解码原始大图。
🖼️ 渐进加载thumbnail(thumbnailRequest)先快速加载小图作为占位,再全尺寸加载,提升体验。
💾 缓存策略diskCacheStrategy(DiskCacheStrategy.RESOURCE)对于大图,推荐只缓存处理后的资源。
skipMemoryCache(true)跳过内存缓存,防止大图挤占宝贵的内存空间。
🎨 解码格式format(DecodeFormat.PREFER_RGB_565)使用RGB_565格式(每个像素占2字节),比默认的ARGB_8888(4字节)节省一半内存。
🧩 专用视图SubsamplingScaleImageView第三方库,支持图片局部显示和手势操作,是加载超长图或超高分辨率图的最佳选择。

16、自定义View步骤时

主要分六步:

  1. 继承合适的View类;
  2. 定义并解析自定义属性;
  3. 重写onMeasure正确测量自身尺寸;
  4. 如果是容器,还需重写onLayout安排子View;
  5. 重写绘制方法 onDraw,使用Canvas和Paint进行绘制
  6. 处理触摸事件 onTouchEvent。

17、内存优化 —— 防泄漏、减开销、防OOM

目标是稳定、高效的内存使用曲线

优化方向核心策略与工具关键实现要点
内存泄漏防治工具:LeakCanary(自动)、Android Profiler(手动堆转储)。 场景Activity/Fragment 被长生命周期对象(单例、静态变量、后台线程)持有。1. 使用 Application Context 替代 Activity Context。 2. Handler 用静态内部类 + WeakReference,并在 onDestroy 中移除回调。 3. 监听器、BroadcastReceiverSensorManager 及时反注册。
大图与Bitmap优化工具:Memory Profiler、adb shell dumpsys meminfo1. 使用 Glide/Picasso 等库(自带内存缓存、尺寸适配)。 2. 加载大图时,使用 BitmapFactory.OptionsinSampleSize 进行采样压缩。 3. 使用 Bitmap.Config.RGB_565(非透明图)。 4. 在 onLowMemory 回调中主动清理缓存。
内存抖动避免工具:Memory Profiler观察分配曲线。1. 避免在循环或高频回调(如onDraw)中创建对象。 2. 使用对象池(如 Pools.SimplePool)复用 MessageRect 等对象。
数据结构与集合-1. 根据场景选择最优集合(SparseArray 替代 HashMap<Integer, Object>)。 2. 避免使用枚举(Enum),改用 @IntDef/@StringDef

18、卡顿与UI渲染优化 —— 保流畅(60fps,即16ms/帧)

核心是减轻主线程负担

优化方向核心策略与工具关键实现要点
布局层级优化工具:Layout Inspector、Systrace。1. 使用 ConstraintLayout 减少嵌套,实现扁平化。 2. 善用 <include><merge>ViewStub。 3. 使用 AsyncLayoutInflater 异步加载复杂布局。
测量/布局/绘制优化工具:GPU过度绘制调试、Profile GPU Rendering。1. 自定义View时,优化onDraw:避免创建对象、使用canvas.clipRect()限制绘制区域。 2. 简化ViewonMeasure/onLayout逻辑。
列表滑动优化工具:RecyclerView专用分析工具。1. RecyclerView 优化: - 使用 DiffUtil 进行增量更新。 - 预加载:setInitialPrefetchItemCount()。 - 优化 ViewHolder 创建,复用池调优。 - 使用 payload 进行局部刷新,避免整项重绑。 2. 分页加载,避免一次性加载所有数据。
主线程耗时操作工具:Systrace、Perfetto。1. 严格遵循:网络、文件、数据库等I/O操作必须在子线程。使用协程(withContext(Dispatchers.IO))、RxJava等。 2. 复杂计算(如JSON解析、列表排序)移出主线程。
动画优化-1. 优先使用属性动画而非补间动画(更高效)。 2. 使用 硬件加速层View.setLayerType)但要谨慎,会增大内存开销。

19、耗电与网络优化 —— 保续航、省流量

目标是减少不必要的后台活动和网络请求

优化方向核心策略与工具关键实现要点
后台任务管控工具:Android Vitals、Battery Historian。1. 使用 WorkManager 处理可延迟的后台任务,系统会批量执行。 2. 使用 JobScheduler 在特定条件(如充电、有网络)下执行任务。 3. 及时释放 WakeLock,避免屏幕关闭后CPU仍被占用。
网络请求优化工具:Charles/Fiddler抓包、Network Profiler。1. 合并请求与减少轮询:使用 WebSocket、长连接替代频繁短连接。 2. 数据压缩与缓存:使用GZIP压缩、合理设置HTTP缓存头、对非实时数据做本地缓存。 3. 图片优化:根据网络状况(Wi-Fi/4G)下发不同分辨率的图片,使用WebP格式。
传感器与定位-1. 使用后及时注销传感器监听。 2. 根据精度需求选择合适的定位模式(GPS vs NETWORK),获取到位置后及时关闭。

20、某电商App商品列表页,快速滑动时卡顿,且退出后内存居高不下。

分析过程

  1. 定位:使用 Systrace 发现滑动时主线程有大量inflateonBindViewHolder耗时;使用 Memory Profiler 发现退出后 Activity 实例未被回收。

  2. 根因

    • 卡顿RecyclerViewItem 布局层级过深(6层),且 onBindViewHolder 中有同步的图片加载和复杂计算。
    • 内存泄漏:在 ViewHolder 中注册了一个全局事件总线监听器,但未在视图销毁时反注册。
  3. 解决方案

    • UI渲染:将 Item 布局重构为 ConstraintLayout(降至3层)。将 onBindViewHolder 中的计算移至后台线程,使用 Glideinto(Target) 异步加载图片。
    • 内存:在 ViewHolderonViewRecycledActivityonDestroy 中,反注册事件监听,并清除对 ImageView 的引用。
    • 列表性能:引入 DiffUtilListAdapter,并使用 payload 进行局部刷新。
  4. 结果:滑动帧率从 45fps 提升至 58fps,退出页面后内存即时释放。

“我会将性能优化看作一个由 ‘度量、分析、优化、监控’ 构成的闭环。具体实施围绕三大支柱展开:

  1. 内存优化:核心是防泄漏(利用LeakCanary)和减开销(Bitmap优化、避免内存抖动),目标是稳定的内存曲线。
  2. 卡顿优化:核心是为主线程减负(布局扁平化、列表优化、异步化),利用Systrace和GPU渲染工具,确保60fps的流畅体验。
  3. 耗电与网络优化:核心是减少不必要的后台活动(使用WorkManager)和网络请求(合并、压缩、缓存)。