《Android 应用开发基础教程》——第十一章:Android 中的图片加载与缓存(Glide 使用详解)

目录

[第十一章:Android 中的图片加载与缓存(Glide 使用详解)](#第十一章:Android 中的图片加载与缓存(Glide 使用详解))

[🔹 11.1 Glide 简介](#🔹 11.1 Glide 简介)

[🔸 11.2 添加 Glide 依赖](#🔸 11.2 添加 Glide 依赖)

[🔸 11.3 基本用法](#🔸 11.3 基本用法)

[✦ 加载网络图片到 ImageView:](#✦ 加载网络图片到 ImageView:)

[✦ 加载本地资源 / 文件 / URI:](#✦ 加载本地资源 / 文件 / URI:)

[🔸 11.4 占位图、错误图、缩略图](#🔸 11.4 占位图、错误图、缩略图)

[🔸 11.5 图片变换:圆角、圆形、裁剪](#🔸 11.5 图片变换:圆角、圆形、裁剪)

[✦ CenterCrop 和 FitCenter:](#✦ CenterCrop 和 FitCenter:)

[✦ GlideTransform:实现圆角或圆形(需引入扩展库):](#✦ GlideTransform:实现圆角或圆形(需引入扩展库):)

[🔸 11.6 缓存策略](#🔸 11.6 缓存策略)

[🔸 11.7 在 RecyclerView 中使用 Glide](#🔸 11.7 在 RecyclerView 中使用 Glide)

[🔸 11.8 清除缓存](#🔸 11.8 清除缓存)

[✅ 实战练习建议](#✅ 实战练习建议)

习题答案

项目结构

[1. MainActivity.java](#1. MainActivity.java)

[2. ImageTextAdapter.java](#2. ImageTextAdapter.java)

[3. GlideUtils.java](#3. GlideUtils.java)

[4. CircleBorderTransform.java](#4. CircleBorderTransform.java)

[5. activity_main.xml](#5. activity_main.xml)

[6. item_image_text.xml](#6. item_image_text.xml)

[7. ImageTextItem.java](#7. ImageTextItem.java)

总结


第十一章:Android 中的图片加载与缓存(Glide 使用详解)

在移动应用中,图片加载是最常见也最耗资源的任务之一。为了提升性能并避免内存泄露,我们通常使用图片加载库。Glide 是 Google 推荐的 Android 图片加载库,功能强大、使用简单,支持图片加载、转换、缓存等操作。


🔹 11.1 Glide 简介

Glide 由 BumpTech 开发,具有以下特点:

  • 支持从网络、本地、资源中加载图片

  • 自动内存缓存与磁盘缓存

  • 支持图片缩放、裁剪、圆角、圆形

  • 支持 GIF 加载

  • 支持 RecyclerView 中高效加载


🔸 11.2 添加 Glide 依赖

build.gradle(:app) 文件中添加:

java 复制代码
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'

🔸 11.3 基本用法

✦ 加载网络图片到 ImageView:

java 复制代码
ImageView imageView = findViewById(R.id.imageView);

Glide.with(this)
     .load("https://example.com/image.jpg")
     .into(imageView);

✦ 加载本地资源 / 文件 / URI:

java 复制代码
// 资源图片
Glide.with(this)
     .load(R.drawable.sample)
     .into(imageView);

// 本地文件
File file = new File(getExternalFilesDir(null), "pic.jpg");
Glide.with(this)
     .load(file)
     .into(imageView);

🔸 11.4 占位图、错误图、缩略图

java 复制代码
Glide.with(this)
     .load("https://example.com/image.jpg")
     .placeholder(R.drawable.loading)    // 加载中显示的图
     .error(R.drawable.error_image)      // 加载失败显示的图
     .thumbnail(0.1f)                    // 显示缩略图
     .into(imageView);

🔸 11.5 图片变换:圆角、圆形、裁剪

✦ CenterCrop 和 FitCenter:

java 复制代码
Glide.with(this)
     .load(url)
     .centerCrop()    // 居中裁剪
     .into(imageView);

✦ GlideTransform:实现圆角或圆形(需引入扩展库):

javascript 复制代码
implementation 'jp.wasabeef:glide-transformations:4.3.0'
java 复制代码
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;

Glide.with(this)
     .load(url)
     .transform(new RoundedCornersTransformation(20, 0)) // 圆角半径 20
     .into(imageView);

🔸 11.6 缓存策略

java 复制代码
Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.ALL)  // 磁盘缓存策略
     .skipMemoryCache(false)                    // 是否跳过内存缓存
     .into(imageView);

常用策略包括:

策略 描述
DiskCacheStrategy.ALL 原图和压缩图都缓存
DiskCacheStrategy.NONE 不缓存任何内容
DiskCacheStrategy.RESOURCE 仅缓存压缩后的图片

🔸 11.7 在 RecyclerView 中使用 Glide

java 复制代码
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    Glide.with(holder.itemView.getContext())
         .load(itemList.get(position).getImageUrl())
         .into(holder.imageView);
}

注意:不要在 Adapter 中使用 with(context.getApplicationContext()),会影响 View 生命周期管理。


🔸 11.8 清除缓存

java 复制代码
// 清除内存缓存(主线程)
Glide.get(context).clearMemory();

// 清除磁盘缓存(子线程)
new Thread(() -> {
    Glide.get(context).clearDiskCache();
}).start();

✅ 实战练习建议

  1. 实现一个图文混排的 RecyclerView 列表,动态加载网络图片

  2. 使用 Glide 加载 GIF 动图

  3. 用 GlideTransform 实现头像圆形 + 外边框效果

  4. 编写工具类 GlideUtils 封装通用加载逻辑


📢 下一章预告:

第十二章:Material Design 组件实战(Toolbar、BottomNavigation、Snackbar 等)


习题答案

项目结构

javascript 复制代码
MainActivity.java
ImageTextAdapter.java
GlideUtils.java
CircleBorderTransform.java
activity_main.xml
item_image_text.xml

1. MainActivity.java

java 复制代码
package com.example.demo;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private ImageTextAdapter adapter;
    private List<ImageTextItem> itemList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 模拟数据
        itemList = new ArrayList<>();
        itemList.add(new ImageTextItem("https://example.com/image1.jpg", "这是描述文字 1"));
        itemList.add(new ImageTextItem("https://example.com/image2.gif", "这是描述文字 2"));
        itemList.add(new ImageTextItem("https://example.com/avatar.png", "这是圆形头像"));

        adapter = new ImageTextAdapter(itemList, this);
        recyclerView.setAdapter(adapter);
    }
}

2. ImageTextAdapter.java

java 复制代码
package com.example.demo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;

public class ImageTextAdapter extends RecyclerView.Adapter<ImageTextAdapter.ViewHolder> {

    private List<ImageTextItem> itemList;
    private Context context;

    public ImageTextAdapter(List<ImageTextItem> itemList, Context context) {
        this.itemList = itemList;
        this.context = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_image_text, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ImageTextItem item = itemList.get(position);

        // 使用 Glide 加载图片
        if (position == 2) {
            // 使用圆形头像 + 边框效果
            GlideUtils.loadCircleWithBorder(context, item.getImageUrl(), holder.imageView, 5, R.color.teal_200);
        } else {
            // 普通图片或 GIF
            GlideUtils.loadImage(context, item.getImageUrl(), holder.imageView);
        }

        holder.textView.setText(item.getDescription());
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
        TextView textView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imageView);
            textView = itemView.findViewById(R.id.textView);
        }
    }
}

3. GlideUtils.java

java 复制代码
package com.example.demo;

import android.content.Context;
import android.graphics.Color;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;

public class GlideUtils {

    // 加载普通图片或 GIF
    public static void loadImage(Context context, String url, ImageView imageView) {
        Glide.with(context)
                .load(url)
                .into(imageView);
    }

    // 加载圆形头像 + 边框效果
    public static void loadCircleWithBorder(Context context, String url, ImageView imageView, int borderWidth, int borderColor) {
        RequestOptions options = new RequestOptions()
                .transform(new CircleBorderTransform(borderWidth, borderColor)); // 自定义 Transform
        Glide.with(context)
                .load(url)
                .apply(options)
                .into(imageView);
    }
}

4. CircleBorderTransform.java

java 复制代码
package com.example.demo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import java.security.MessageDigest;

public class CircleBorderTransform extends BitmapTransformation {

    private final int borderWidth;
    private final int borderColor;

    public CircleBorderTransform(int borderWidth, int borderColor) {
        this.borderWidth = borderWidth;
        this.borderColor = borderColor;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        int diameter = Math.min(toTransform.getWidth(), toTransform.getHeight());
        int radius = diameter / 2;

        Bitmap result = pool.get(diameter + borderWidth * 2, diameter + borderWidth * 2, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setAntiAlias(true);

        // 绘制圆形头像
        RectF rectF = new RectF(borderWidth, borderWidth, diameter + borderWidth, diameter + borderWidth);
        canvas.drawOval(rectF, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(toTransform, null, rectF, paint);

        // 绘制边框
        paint.setXfermode(null);
        paint.setColor(borderColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(borderWidth);
        canvas.drawOval(rectF, paint);

        return result;
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
        messageDigest.update(("CircleBorderTransform" + borderWidth + borderColor).getBytes());
    }
}

5. activity_main.xml

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" />
</LinearLayout>

6. item_image_text.xml

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop"
        android:contentDescription="Image" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Description"
        android:textSize="16sp"
        android:paddingStart="16dp"
        android:gravity="center_vertical" />
</LinearLayout>

7. ImageTextItem.java

java 复制代码
package com.example.demo;

public class ImageTextItem {
    private String imageUrl;
    private String description;

    public ImageTextItem(String imageUrl, String description) {
        this.imageUrl = imageUrl;
        this.description = description;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public String getDescription() {
        return description;
    }
}

总结

  1. 图文混排 :通过 RecyclerView 展示图片和文字。
  2. 动态加载网络图片 :使用 Glide 加载普通图片和 GIF 动图。
  3. 圆形头像 + 边框 :通过自定义 CircleBorderTransform 实现。
  4. 工具类封装GlideUtils 封装了通用的图片加载逻辑。
相关推荐
RoboWizard35 分钟前
移动固态硬盘无法被电脑识别怎么办?
大数据·人工智能·缓存·电脑·金士顿
程序员江同学43 分钟前
Kotlin 技术月报 | 2025 年 9 月
android·kotlin
码农的小菜园1 小时前
探究ContentProvider(一)
android
时光少年3 小时前
Compose AnnotatedString实现Html样式解析
android·前端
hnlgzb4 小时前
安卓中,kotlin如何写app界面?
android·开发语言·kotlin
jzlhll1234 小时前
deepseek kotlin flow快生产者和慢消费者解决策略
android·kotlin
火柴就是我4 小时前
Android 事件分发之动态的决定某个View来处理事件
android
一直向钱4 小时前
FileProvider 配置必须针对 Android 7.0+(API 24+)做兼容
android
zh_xuan4 小时前
Android 消息循环机制
android
ajassi20005 小时前
开源 java android app 开发(十五)自定义绘图控件--仪表盘
android·java·开源