Skip to content

07_图片加载_Glide

目录


Glide 概述

1.1 什么是 Glide

Glide 是 Google 开源的图片加载库,专注于 Android 平台的图片加载、缓存和内存管理。它提供了简单强大的 API,支持各种图片格式和复杂的加载场景。

核心特性

  • 简单易用的 API
  • 强大的缓存机制
  • 内存管理自动化
  • 支持多种图片格式
  • 可定制的图片转换
  • 高性能和稳定性

1.2 发展历程

2014 年:Glide 1.0 发布
2015 年:Glide 3.0 重大重构
2016 年:Glide 4.0 AndroidX 支持
2020 年:Glide 4.15+ 持续优化
2024 年:Glide 成为行业标准

1.3 核心概念

Glide 的核心组件

┌─────────────────────────────────┐
│           Glide                 │
├─────────────────────────────────┤
│  加载器 (Loader)                │
│    - 负责获取数据源             │
├─────────────────────────────────┤
│  解码器 (Decoder)               │
│    - 负责解析数据为 Bitmap       │
├─────────────────────────────────┤
│  编码器 (Encoder)               │
│    - 负责 Bitmap 转为字节流       │
├─────────────────────────────────┤
│  模型加载器 (ModelLoader)       │
│    - 负责 URL/File 等资源解析     │
├─────────────────────────────────┤
│  数据转换 (DataTransform)       │
│    - 负责图片转换(圆角等)      │
├─────────────────────────────────┤
│  缓存 (Cache)                   │
│    - 内存缓存 + 磁盘缓存        │
└─────────────────────────────────┘

1.4 Glide 架构

整体架构

┌────────────────────────────────────┐
│         应用层                      │
│   Glide.with().load().into()        │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        GlideModule                 │
│     (配置和扩展点)                  │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        GlideBuilder                │
│     (构建 Glide 实例)                │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        Glide                       │
│     (核心调度器)                    │
├────────────────────────────────────┤
│  - DataFetcher (数据获取)           │
│  - DecodeCallback (解码回调)        │
│  - Target (目标视图)                │
└────────────────────────────────────┘

Glide 基础使用

2.1 基本加载

加载网络图片

kotlin
// 基本用法
Glide.with(context)
    .load("https://example.com/image.jpg")
    .into(imageView)

// 在 Fragment 中使用(推荐)
Glide.with(fragment)
    .load(url)
    .into(imageView)

// 在 RecyclerView Adapter 中
Glide.with(holder.itemView.context)
    .load(url)
    .into(imageView)

加载本地图片

kotlin
// Drawable
Glide.with(context)
    .load(R.drawable.image)
    .into(imageView)

// File
Glide.with(context)
    .load(File("/path/to/image.jpg"))
    .into(imageView)

// Uri
Glide.with(context)
    .load(contentUri)
    .into(imageView)

加载资源

kotlin
// 资源路径
Glide.with(context)
    .load("res://image.jpg")
    .into(imageView)

2.2 异步和同步加载

异步加载(默认)

kotlin
// 异步加载,不阻塞主线程
Glide.with(context)
    .load(url)
    .into(imageView)

同步加载

kotlin
// 同步加载,返回 Target
val target = Glide.with(context)
    .load(url)
    .submit(width, height)

// 获取 Bitmap
val bitmap = target.get()

// 或者使用 asBitmap().submit()
val bitmap = Glide.with(context)
    .asBitmap()
    .load(url)
    .submit()
    .get()

2.3 加载到不同目标

加载到 ImageView

kotlin
Glide.with(context)
    .load(url)
    .into(imageView)

加载到 SimpleDraweeView(Fresco)

kotlin
// 需要先集成 Fresco
val draweeView = SimpleDraweeView(context)
Glide.with(context)
    .load(url)
    .into(draweeView)

加载到自定义 Target

kotlin
class CustomTarget : CustomTarget<Bitmap>() {
    override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
        // 图片加载完成
        processImage(resource)
    }
    
    override fun onLoadFailed(error: Throwable) {
        // 加载失败
    }
}

val target = CustomTarget()
Glide.with(context)
    .load(url)
    .into(target)

// 记得释放
target.clear()

加载到 Bitmap(不显示)

kotlin
val listener = object : BitmapLoadListener {
    override fun onResourceReady(
        resource: Bitmap,
        model: Any?,
        target: Target<Bitmap>,
        modelLoader: ModelLoader<*, *>
    ) {
        // 处理 Bitmap
    }
}

Glide.with(context)
    .asBitmap()
    .load(url)
    .listener(listener)
    .preload() // 只预加载

2.4 预加载

预加载图片

kotlin
// 预加载单个图片
Glide.with(context)
    .load(url)
    .preload()

// 预加载多个图片
Glide.with(context)
    .preload(url1, url2, url3)

列表预加载

kotlin
class PreloadTransformation : ObjectTransitionTransformation<String, Bitmap>() {
    // 自定义预加载转换
}

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        val layoutManager = recyclerView.layoutManager as LinearLayoutManager
        val firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
        val visibleItemCount = layoutManager.childCount
        
        // 预加载下一页
        for (i in visibleItemCount until visibleItemCount + 5) {
            if (i < items.size) {
                Glide.with(recyclerView.context)
                    .load(items[i].imageUrl)
                    .preload()
            }
        }
    }
})

缓存机制

3.1 多级缓存架构

Glide 缓存层级

┌──────────────────────────────┐
│   资源缓存 (Resource Cache)   │
│   - 内存中存储转换后的资源     │
├──────────────────────────────┤
│   数据缓存 (Data Cache)       │
│   - 内存中存储原始数据         │
├──────────────────────────────┤
│   磁盘缓存 (Disk Cache)       │
│   - 存储原始数据和转换后数据   │
└──────────────────────────────┘

缓存流程

1. 检查资源缓存(内存)
   └─ 命中 -> 直接使用

2. 检查数据缓存(内存)
   └─ 命中 -> 解码后使用

3. 检查磁盘缓存
   └─ 命中 -> 读取并解码

4. 从网络/本地加载
   └─ 存储到各级缓存

3.2 内存缓存

配置内存缓存

kotlin
// 默认配置(应用可用内存的 15%)
GlideMemoryCacheModule(
    LruResourceCache(context),
    LruBitmapCache(context)
)

// 自定义配置
class AppGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, options: Options) {
        options.set(
            MemorySizeOption.MEMORY_CACHE_SIZE_BITS,
            16 // 64MB (2^16 KB)
        )
        options.set(
            MemorySizeOption.RESOURCE_MEMORY_CACHE_SIZE_BITS,
            16
        )
    }
    
    override fun isManifestParsingEnabled(): Boolean {
        return false // 禁用清单解析
    }
}

// 在清单文件中注册
<application>
    <meta-data
        android:name="com.example.AppGlideModule"
        android:value="GlideModule" />
</application>

手动管理内存缓存

kotlin
// 获取 Glide 实例
val glide = Glide.with(context)

// 清除内存缓存
glide.memoryCache.clear()

// 清除资源缓存
glide.clearMemoryCache()

// 获取缓存统计
val memoryCache = glide.memoryCache
val size = memoryCache.size
val limit = memoryCache.limit

3.3 磁盘缓存

配置磁盘缓存

kotlin
class AppGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, options: Options) {
        // 磁盘缓存大小(200MB)
        options.set(
            DiskCache.Factory.classifier,
            InternalCacheDiskCacheFactory(context, 200 * 1024 * 1024)
        )
        
        // 磁盘缓存路径
        options.set(
            DiskCache.Path.classifier,
            context.cacheDir.resolve("glide")
        )
    }
}

磁盘缓存策略

kotlin
Glide.with(context)
    .load(url)
    .diskCacheStrategy(DiskCacheStrategy.ALL) // 缓存原始和转换后的图片
    .into(imageView)

// 策略选项
enum class DiskCacheStrategy {
    ALL,        // 缓存原始和转换后(默认)
    NONE,       // 不缓存
    DATA,       // 只缓存原始数据
    RESOURCE    // 只缓存转换后的资源
}

磁盘缓存管理

kotlin
// 清除磁盘缓存
Glide.with(context)
    .clearDiskCache()

// 获取磁盘缓存统计
val diskCache = Glide.get(context).diskCache
val size = diskCache.size
val limit = diskCache.limit

3.4 缓存优先级

配置缓存优先级

kotlin
Glide.with(context)
    .load(url)
    .priority(Priority.HIGH) // HIGH, NORMAL, LOW
    .into(imageView)

优先级影响

  • 高优先级任务先执行
  • 高优先级任务占用更多缓存空间
  • 低优先级任务可能被取消

3.5 缓存失效

手动失效缓存

kotlin
// 失效单个资源
Glide.with(context)
    .clear(url)

// 失效所有缓存
Glide.with(context)
    .clearMemoryCache()
    .clearDiskCache()

// 失效特定类型缓存
Glide.get(context)
    .context
    .getCache()
    .clear()

版本管理

kotlin
// 使用版本号管理缓存
Glide.with(context)
    .load(url)
    .version(1) // 版本号改变时缓存失效
    .into(imageView)

占位图与错误图

4.1 占位图

基本占位图

kotlin
Glide.with(context)
    .load(url)
    .placeholder(R.drawable.placeholder)
    .into(imageView)

动态占位图

kotlin
Glide.with(context)
    .load(url)
    .placeholder(ColorDrawable(Color.GRAY))
    .into(imageView)

交叉淡入占位图

kotlin
Glide.with(context)
    .load(url)
    .placeholder(R.drawable.placeholder)
    .crossFade()
    .into(imageView)

4.2 错误图

基本错误图

kotlin
Glide.with(context)
    .load(url)
    .error(R.drawable.error)
    .into(imageView)

自定义错误处理

kotlin
Glide.with(context)
    .load(url)
    .error { throwable ->
        // 处理错误
        Log.e("Glide", "Load error", throwable)
        R.drawable.error
    }
    .into(imageView)

错误图策略

kotlin
Glide.with(context)
    .load(url)
    .error(R.drawable.error)
    .fallback(R.drawable.fallback) // 如果占位图也失败
    .into(imageView)

4.3 加载中状态

自定义加载中状态

kotlin
Glide.with(context)
    .load(url)
    .placeholder(R.drawable.loading)
    .error(R.drawable.error)
    .into(object : CustomTarget<Drawable>() {
        override fun onResourceReady(
            resource: Drawable,
            transition: Transition<in Drawable>?
        ) {
            imageView.setImageDrawable(resource)
        }
        
        override fun onLoadStarted(model: Any?) {
            imageView.setImageResource(R.drawable.loading)
        }
        
        override fun onLoadFailed(error: Throwable?) {
            imageView.setImageResource(R.drawable.error)
        }
    })

图片转换

5.1 内置转换

圆角

kotlin
// 圆角矩形
Glide.with(context)
    .load(url)
    .transform(RoundedCornersTransformation(20))
    .into(imageView)

// 圆形
Glide.with(context)
    .load(url)
    .circleCrop()
    .into(imageView)

// 渐变圆角
Glide.with(context)
    .load(url)
    .transform(
        RoundedCornersTransformation(
            context,
            20f,
            0f,
            RoundedCornersTransformation.Options.BOTTOM_RIGHT
        )
    )
    .into(imageView)

缩放

kotlin
// 居中裁剪
Glide.with(context)
    .load(url)
    .centerCrop()
    .into(imageView)

// 适应
Glide.with(context)
    .load(url)
    .centerInside()
    .into(imageView)

// 拉伸
Glide.with(context)
    .load(url)
    .centerInside()
    .into(imageView)

滤镜

kotlin
// 灰度
Glide.with(context)
    .load(url)
    .transform(GrayscaleTransformation())
    .into(imageView)

// 自定义滤镜
class SepiaTransformation : BitmapTransformation() {
    override fun transform(
        pool: Pool<Bitmap>,
        toTransform: Bitmap,
        outWidth: Int,
        outHeight: Int
    ): Bitmap {
        val bitmap = toTransform.copy(Bitmap.Config.ARGB_8888, true)
        val canvas = Canvas(bitmap)
        
        val paint = Paint().apply {
            colorFilter = ColorMatrixColorFilter(floatArrayOf(
                0.93, 0.66, 0.20, 0, 0,
                0.69, 0.66, 0.26, 0, 0,
                0.52, 0.66, 0.40, 0, 0,
                0, 0, 0, 1, 0
            ))
        }
        
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return bitmap
    }
    
    override fun getId(): String = "sepia_transformation"
}

5.2 自定义转换

实现 BitmapTransformation

kotlin
class CustomTransformation : BitmapTransformation() {
    
    override fun transform(
        pool: Pool<Bitmap>,
        toTransform: Bitmap,
        outWidth: Int,
        outHeight: Int
    ): Bitmap {
        // 1. 从池获取 Bitmap
        val bitmap = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888)
            ?: Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888)
        
        // 2. 执行转换
        val canvas = Canvas(bitmap)
        // 自定义绘制逻辑
        
        // 3. 返回 Bitmap
        return bitmap
    }
    
    override fun getId(): String {
        return "custom_transformation"
    }
}

// 使用
Glide.with(context)
    .load(url)
    .transform(CustomTransformation())
    .into(imageView)

多转换组合

kotlin
Glide.with(context)
    .load(url)
    .transform(
        object : MultiTransformation<Bitmap>() {
            init {
                append(RoundedCornersTransformation(20f))
                append(GrayscaleTransformation())
            }
        }
    )
    .into(imageView)

5.3 尺寸调整

固定尺寸

kotlin
Glide.with(context)
    .load(url)
    .override(100, 100)
    .into(imageView)

按比例缩放

kotlin
Glide.with(context)
    .load(url)
    .sizeMultiplier(0.5f) // 50% 尺寸
    .into(imageView)

目标尺寸

kotlin
Glide.with(context)
    .load(url)
    .into(imageView) // 自动使用 ImageView 尺寸

图片解码

6.1 支持的格式

内置支持

JPEG
PNG
GIF
WebP
WebP Animated
Png8
Bitmap

扩展支持

// 添加依赖
implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'

6.2 解码选项

指定配置

kotlin
Glide.with(context)
    .asBitmap()
    .load(url)
    .override(100, 100)
    .into(imageView)

Glide.with(context)
    .asGif()
    .load(url)
    .into(imageView)

Glide.with(context)
    .asDrawable()
    .load(url)
    .into(imageView)

解码选项

kotlin
Glide.with(context)
    .load(url)
    .apply(
        RequestOptions()
            .format(PictureFormat.JPEG)
            .priority(Priority.HIGH)
    )
    .into(imageView)

6.3 自定义解码器

实现 ResourceDecoder

kotlin
class CustomDecoder : ResourceDecoder<CustomData, Bitmap> {
    
    override fun handles(source: CustomData, options: Options): Boolean {
        return source.isCustomFormat
    }
    
    override fun decode(
        source: CustomData,
        width: Int,
        height: Int,
        options: Options
    ): Bitmap? {
        return try {
            BitmapFactory.decodeStream(source.inputStream)
        } catch (e: Exception) {
            null
        }
    }
}

// 注册解码器
class AppGlideModule : AppGlideModule() {
    override fun registerComponents(context: Context, glide: Glide) {
        glide.registry.add(
            CustomData::class.java,
            Bitmap::class.java,
            CustomDecoder()
        )
    }
}

内存管理

7.1 内存泄漏预防

自动管理生命周期

kotlin
// ✅ 推荐:使用 Fragment/Activity 上下文
Glide.with(fragment).load(url).into(imageView)

// ✅ 推荐:使用 Application 上下文(预加载)
Glide.with(applicationContext).load(url).preload()

// ❌ 不推荐:使用 View 上下文(可能泄漏)
Glide.with(itemView).load(url).into(imageView)

手动清理

kotlin
// 在 onDestroy 中清理
override fun onDestroyView() {
    super.onDestroyView()
    Glide.with(this).clearMemoryCache()
}

// 清理特定 Target
val target = Glide.with(context)
    .load(url)
    .into(customTarget)

target.clear()

使用 WeakReference

kotlin
class ViewModel {
    private val contextRef = WeakReference<Context>(context)
    
    fun loadImage() {
        contextRef.get()?.let { context ->
            Glide.with(context).load(url).into(imageView)
        }
    }
}

7.2 内存优化

限制缓存大小

kotlin
class AppGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, options: Options) {
        // 设置内存缓存大小为 30MB
        options.set(
            MemorySizeOption.MEMORY_CACHE_SIZE_BITS,
            25 // 2^25 bytes = 32MB
        )
    }
}

使用合适的 Bitmap 配置

kotlin
Glide.with(context)
    .load(url)
    .override(100, 100)
    .bitmapConfig(Bitmap.Config.RGB_565) // 减少内存占用
    .into(imageView)

及时回收

kotlin
// 在 RecyclerView 中
override fun onViewRecycled(holder: ViewHolder) {
    Glide.with(holder.itemView.context)
        .clear(holder.imageView)
    super.onViewRecycled(holder)
}

7.3 内存监控

监控内存使用

kotlin
class GlideMemoryMonitor {
    fun monitorMemory(context: Context) {
        val glide = Glide.get(context)
        val memoryCache = glide.memoryCache
        
        Thread {
            while (true) {
                Log.d("Glide", "Memory Cache Size: ${memoryCache.size}")
                Thread.sleep(1000)
            }
        }.start()
    }
}

Glide vs Picasso vs Coil

8.1 对比表

特性GlidePicassoCoil
维护状态活跃已停止活跃
内存管理优秀良好优秀
缓存机制多级简单简单
协程支持通过扩展不支持原生支持
GIF 支持原生需扩展需扩展
WebP 支持原生需扩展原生
自定义性
学习曲线中等简单简单
性能优秀良好优秀
体积较大

8.2 使用场景

Glide

  • 大型应用
  • 需要高级功能
  • 复杂图片处理
  • 多种数据源

Picasso

  • 小型应用
  • 简单图片加载
  • 维护旧项目

Coil

  • Kotlin 优先
  • 协程集成
  • 现代 Android 开发

8.3 代码对比

Glide

kotlin
Glide.with(context)
    .load(url)
    .placeholder(R.drawable.placeholder)
    .error(R.drawable.error)
    .centerCrop()
    .into(imageView)

Picasso

kotlin
Picasso.get()
    .load(url)
    .placeholder(R.drawable.placeholder)
    .error(R.drawable.error)
    .centerCrop()
    .fit()
    .into(imageView)

Coil

kotlin
imageView.load(url) {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    crossfade(true)
    size(Size.ORIGINAL)
}

性能优化

9.1 加载优化

按需加载

kotlin
// 只在可见时加载
class ImageAdapter : RecyclerView.Adapter<ViewHolder>() {
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        if (isViewVisible(holder.itemView)) {
            Glide.with(holder.itemView.context)
                .load(items[position].url)
                .into(holder.imageView)
        }
    }
    
    private fun isViewVisible(view: View): Boolean {
        // 实现可见性检查
    }
}

尺寸匹配

kotlin
// 根据 ImageView 尺寸加载
Glide.with(context)
    .load(url)
    .override(imageView.width, imageView.height)
    .into(imageView)

图片格式优化

kotlin
// 优先使用 WebP
Glide.with(context)
    .load(url)
    .format(PictureFormat.WEBP)
    .into(imageView)

9.2 缓存优化

合理配置缓存

kotlin
class AppGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, options: Options) {
        // 内存缓存:15% 应用内存
        // 磁盘缓存:200MB
        options.set(
            DiskCache.Factory.classifier,
            InternalCacheDiskCacheFactory(context, 200 * 1024 * 1024)
        )
    }
}

清理策略

kotlin
// 定期清理旧缓存
Glide.get(context)
    .context
    .getCache()
    .trimToSize(maxSize)

9.3 并发优化

限制并发数

kotlin
class GlideConfiguration {
    companion object {
        const val MAX_CONCURRENT = 4
    }
}

// Glide 内部已优化并发

优先级管理

kotlin
Glide.with(context)
    .load(url)
    .priority(Priority.HIGH) // 重要图片
    .into(imageView)

代码示例

10.1 完整的图片加载方案

kotlin
object ImageLoader {
    
    fun load(
        context: Context,
        url: String,
        imageView: ImageView,
        placeholder: Int = R.drawable.placeholder,
        error: Int = R.drawable.error,
        cornerRadius: Int = 0
    ) {
        val glideRequest = Glide.with(context)
            .load(url)
            .placeholder(placeholder)
            .error(error)
            .centerCrop()
            .transition(CrossFade())
            
        if (cornerRadius > 0) {
            glideRequest.transform(RoundedCornersTransformation(cornerRadius.toFloat()))
        }
        
        glideRequest.into(imageView)
    }
    
    fun loadCircleAvatar(
        context: Context,
        url: String,
        imageView: ImageView
    ) {
        Glide.with(context)
            .load(url)
            .placeholder(R.drawable.avatar_placeholder)
            .error(R.drawable.avatar_error)
            .circleCrop()
            .into(imageView)
    }
    
    fun loadImageList(
        context: Context,
        url: String,
        imageView: ImageView,
        position: Int
    ) {
        // 列表图片优化
        val targetSize = 100 // 列表项尺寸
        
        Glide.with(context)
            .load(url)
            .override(targetSize, targetSize)
            .placeholder(R.drawable.list_placeholder)
            .error(R.drawable.list_error)
            .centerCrop()
            .tag("list_$position")
            .into(imageView)
    }
    
    fun preload(context: Context, urls: List<String>) {
        Glide.with(context)
            .preload(*urls.toTypedArray())
    }
    
    fun clear(context: Context, imageView: ImageView) {
        Glide.with(context).clear(imageView)
    }
}

10.2 RecyclerView 优化

kotlin
class OptimizedImageAdapter : RecyclerView.Adapter<OptimizedImageAdapter.ViewHolder>() {
    
    private val items = mutableListOf<ImageItem>()
    private val imageCache = LruCache<String, Drawable>(20)
    
    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.image)
        
        fun bind(item: ImageItem, position: Int) {
            // 检查缓存
            imageCache.get(item.url)?.let { drawable ->
                imageView.setImageDrawable(drawable)
                return
            }
            
            // 加载图片
            ImageLoader.loadList(
                itemView.context,
                item.url,
                imageView,
                position
            )
        }
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_image, parent, false)
        return ViewHolder(view)
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(items[position], position)
    }
    
    override fun onViewRecycled(holder: ViewHolder) {
        ImageLoader.clear(holder.itemView.context, holder.imageView)
        super.onViewRecycled(holder)
    }
    
    override fun getItemCount() = items.size
}

面试考点

基础题

1. Glide 的缓存机制?

三级缓存:
1. 资源缓存(内存)
2. 数据缓存(内存)
3. 磁盘缓存

缓存策略:
- DiskCacheStrategy.ALL
- DiskCacheStrategy.NONE
- DiskCacheStrategy.DATA
- DiskCacheStrategy.RESOURCE

2. Glide 的核心组件?

- Loader(加载器)
- Decoder(解码器)
- Encoder(编码器)
- ModelLoader(模型加载器)
- DataTransform(数据转换)
- Cache(缓存)

3. 如何优化 Glide 性能?

1. 合理配置缓存大小
2. 按需加载图片尺寸
3. 使用合适的图片格式
4. 避免内存泄漏
5. 使用预加载

进阶题

1. Glide 的生命周期管理?

- 使用 Fragment/Activity 上下文
- 手动清理 Target
- 使用 WeakReference
- RecyclerView 中及时清理

2. 如何实现自定义图片转换?

实现 BitmapTransformation 接口:
- transform() 方法执行转换
- getId() 返回唯一标识
- 使用 Pool 复用 Bitmap

3. Glide 和 Picasso 的区别?

Glide:
- 功能更强大
- 缓存机制更完善
- 支持更多格式
- 可定制性更高

Picasso:
- 更简单
- 体积更小
- 已停止维护

高级题

1. Glide 的源码架构?

- GlideModule:配置入口
- GlideBuilder:构建器
- Glide:核心调度
- DataFetcher:数据获取
- DecodeCallback:解码回调
- Target:目标视图

2. 如何解决 Glide 的内存问题?

1. 调整缓存大小
2. 使用合适的 Bitmap 配置
3. 及时清理缓存
4. 避免大图片
5. 使用 WebP 格式

3. 如何实现图片加载的优先级?

Priority.HIGH
Priority.NORMAL
Priority.LOW

影响缓存和调度顺序

总结

核心要点

  1. 基础使用

    • with().load().into()
    • 支持多种数据源
    • 异步加载
  2. 缓存机制

    • 多级缓存
    • 可配置策略
    • 自动管理
  3. 图片转换

    • 圆角、裁剪
    • 自定义转换
    • 滤镜效果
  4. 性能优化

    • 按需加载
    • 尺寸匹配
    • 格式优化

最佳实践

kotlin
// 1. 使用 Fragment 上下文
Glide.with(fragment).load(url).into(imageView)

// 2. 配置占位图和错误图
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)

// 3. 按需尺寸加载
.override(width, height)

// 4. 使用合适的缓存策略
.diskCacheStrategy(DiskCacheStrategy.ALL)

// 5. 及时清理
Glide.with(context).clear(imageView)

本文约 12000 字,涵盖了 Glide 的核心知识点。