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

目录

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

🔹 11.1 Glide 简介

🔸 11.2 添加 Glide 依赖

🔸 11.3 基本用法

✦ 加载网络图片到 ImageView:

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

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

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

✦ CenterCrop 和 FitCenter:

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

🔸 11.6 缓存策略

🔸 11.7 在 RecyclerView 中使用 Glide

🔸 11.8 清除缓存

✅ 实战练习建议

习题答案

项目结构

1. MainActivity.java

2. ImageTextAdapter.java

3. GlideUtils.java

4. CircleBorderTransform.java

5. activity_main.xml

6. item_image_text.xml

7. ImageTextItem.java

总结


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

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


🔹 11.1 Glide 简介

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

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

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

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

  • 支持 GIF 加载

  • 支持 RecyclerView 中高效加载


🔸 11.2 添加 Glide 依赖

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

implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'


🔸 11.3 基本用法

✦ 加载网络图片到 ImageView:

ImageView imageView = findViewById(R.id.imageView);Glide.with(this).load("https://example.com/image.jpg").into(imageView);


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

// 资源图片
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 占位图、错误图、缩略图

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:

Glide.with(this).load(url).centerCrop()    // 居中裁剪.into(imageView);


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

implementation 'jp.wasabeef:glide-transformations:4.3.0'

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


🔸 11.6 缓存策略

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

常用策略包括:

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

🔸 11.7 在 RecyclerView 中使用 Glide

@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 清除缓存

// 清除内存缓存(主线程)
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 等)


习题答案

项目结构

MainActivity.java
ImageTextAdapter.java
GlideUtils.java
CircleBorderTransform.java
activity_main.xml
item_image_text.xml

1. MainActivity.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;@Overrideprotected 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

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@Overridepublic 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);}@Overridepublic 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 {// 普通图片或 GIFGlideUtils.loadImage(context, item.getImageUrl(), holder.imageView);}holder.textView.setText(item.getDescription());}@Overridepublic 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

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 {// 加载普通图片或 GIFpublic 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)); // 自定义 TransformGlide.with(context).load(url).apply(options).into(imageView);}
}

4. CircleBorderTransform.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;}@Overrideprotected 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;}@Overridepublic void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {messageDigest.update(("CircleBorderTransform" + borderWidth + borderColor).getBytes());}
}

5. activity_main.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.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="8dp" />
</LinearLayout>

6. item_image_text.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"><ImageViewandroid:id="@+id/imageView"android:layout_width="100dp"android:layout_height="100dp"android:scaleType="centerCrop"android:contentDescription="Image" /><TextViewandroid: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

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 封装了通用的图片加载逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79112.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AE模板 300个故障干扰损坏字幕条标题动画视频转场预设

这个AE模板提供了300个故障干扰损坏字幕条标题动画视频转场预设&#xff0c;让您的视频具有炫酷的故障效果。无论是预告片、宣传片还是其他类型的视频&#xff0c;这个模板都能带给您令人惊叹的故障运动标题效果。该模板无需任何外置插件或脚本&#xff0c;只需一键点击即可应用…

在 Python 中,以双下划线开头和结尾的函数(如 `__str__`、`__sub__` 等)

在 Python 中&#xff0c;以双下划线开头和结尾的函数&#xff08;如 __str__、__sub__ 等&#xff09;被称为特殊方法&#xff08;Special Methods&#xff09;或魔术方法&#xff08;Magic Methods&#xff09;。它们确实是 Python 内置的&#xff0c;用于定义类的行为&#…

git问题记录-如何切换历史提交分支,且保留本地修改

问题记录 我在本地编写了代码&#xff0c;突然想查看之前提交的代码&#xff0c;并且想保留当前所在分支所做的修改 通过git stash对本地的代码进行暂存 使用git checkout <commit-hash>切换到之前的提交记录。 查看完之后我想切换回来&#xff0c;恢复暂存的本地代码…

Github开通第三方平台OAuth登录及Java对接步骤

调研起因&#xff1a; 准备搞AI Agent海外项目&#xff0c;有相当一部分用户群体是程序员&#xff0c;所以当然要接入Github这个全球最大的同性交友网站了&#xff0c;让用户使用Github账号一键完成注册或登录。 本教程基于Web H5界面进行对接&#xff0c;同时也提供了spring-…

期刊、出版社、索引数据库

image 1、研究人员向期刊或者会议投稿&#xff0c;交注册费和相应的审稿费等相关费用[1]&#xff1b; 2、会议组织者和期刊联系出版社&#xff0c;交出版费用&#xff1b; 3、出版社将论文更新到自己的数据库中&#xff0c;然后将数据库卖给全世界各大高校或企业&#xff1b; 4…

Transformer 模型及深度学习技术应用

近年来&#xff0c;随着卷积神经网络&#xff08;CNN&#xff09;等深度学习技术的飞速发展&#xff0c;人工智能迎来了第三次发展浪潮&#xff0c;AI技术在各行各业中的应用日益广泛。 注意力机制&#xff1a;理解其在现代深度学习中的关键作用&#xff1b; Transformer模型…

zynq7035的arm一秒钟最多可以支持触发多少次中断

一、概述 1.关于zynq7035的ARM处理器一秒能够支持多少次中断触发&#xff0c;需要综合来考虑。需要确定ARM处理器的参数&#xff0c;目前zynq7000系列&#xff0c;使用的双核Cortex-A9处理器。其中主频大概在500MHZ~1GHZ左右&#xff0c;不同的用户配置的主频可能稍微有差别。 …

数据结构与算法:图论——最短路径

最短路径 先给出一些leetcode算法题&#xff0c;以后遇见了相关题目再往上增加 最短路径的4个常用算法是Floyd、Bellman-Ford、SPFA、Dijkstra。不同应用场景下&#xff0c;应有选择地使用它们&#xff1a; 图的规模小&#xff0c;用Floyd。若边的权值有负数&#xff0c;需要…

[android]MT6835 Android 关闭selinux方法

Selinux SELinux is an optional feature of the Linux kernel that provides support to enforce access control security policies to enforce MAC. It is based on the LSM framework. Working with SELinux on Android – LineageOS Android 关闭selinux MT6835 Android…

【Linux网络编程】http协议的状态码,常见请求方法以及cookie-session

本文专栏&#xff1a;Linux网络编程 目录 一&#xff0c;状态码 重定向状态码 1&#xff0c;永久重定向&#xff08;301 Moved Permanently&#xff09; 2&#xff0c;临时重定向&#xff08;302 Found&#xff09; 二&#xff0c;常见请求方法 1&#xff0c;HTTP常见Hea…

当神经网络突破摩尔定律:探索大模型时代的算力新纪元

当摩尔定律熄灭后&#xff1a;AI算力革命如何重塑技术文明的底层逻辑 一、摩尔定律的黄昏&#xff1a;物理极限与经济理性的双重困境 当英特尔在1965年提出摩尔定律时&#xff0c;没有人预料到这个每18-24个月将芯片晶体管数量翻倍的预言会成为现代计算文明的基石。半个世纪以…

位运算题目:寻找重复数

文章目录 题目标题和出处难度题目描述要求示例数据范围进阶 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 解法三思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;寻找重复数 出处&#xff1a;287. 寻找重复数 难度 6 级 题目描述 要…

Elasticsearch:没有 “AG” 的 RAG?

作者&#xff1a;来自 Elastic Gustavo Llermaly 了解如何利用语义搜索和 ELSER 构建一个强大且视觉上吸引人的问答体验&#xff0c;而无需使用 LLMs。 想要获得 Elastic 认证&#xff1f;查看下一期 Elasticsearch Engineer 培训的时间&#xff01; Elasticsearch 拥有众多新…

linux下安装ollama网不好怎么办?

文章目录 前言kkgithub下载脚本,而不是直接运行修改脚本修改权限还是不行?前言 今天想在linux上面更新一下ollama,于是去到官网: https://ollama.com/download/linux linux下安装ollama还是挺简单的: curl -fsSL https://ollama.com/install.sh | sh我也是特别嗨皮地就…

相机-IMU联合标定:相机-IMU外参标定

文章目录 📚简介🚀标定工具kalibr🚀标定数据录制🚀相机-IMU外参标定📚简介 在 VINS(视觉惯性导航系统) 中,相机-IMU外参标定 是确保多传感器数据时空统一的核心环节,其作用可概括为以下关键点: 坐标系对齐(空间同步),外参误差会导致视觉特征点投影与IMU预积…

基于 Java 的实现前端组装查询语句,后端直接执行查询方案,涵盖前端和后端的设计思路

1. 前端设计 前端负责根据用户输入或交互条件,动态生成查询参数,并通过 HTTP 请求发送到后端。 前端逻辑: 提供用户界面(如表单、筛选器等),让用户选择查询条件。将用户选择的条件组装成 JSON 格式的查询参数。发送 HTTP 请求(如 POST 或 GET)到后端。示例: 假设用…

[STM32] 4-2 USART与串口通信(2)

文章目录 前言4-2 USART与串口通信(2)数据发送过程双缓冲与连续发送数据发送过程中的问题 数据接收过程TXE标志位&#xff08;发送数据寄存器空&#xff09;TC标志位&#xff08;发送完成标志位&#xff09;单个数据的发送数据的连续发送 接收过程中遇到的问题问题描述&#xf…

Qt多线程TCP服务器实现指南

在Qt中实现多线程TCP服务器可以通过为每个客户端连接分配独立的线程来处理&#xff0c;以提高并发性能。以下是一个分步实现的示例&#xff1a; 1. 自定义工作线程类&#xff08;处理客户端通信&#xff09; // workerthread.h #include <QObject> #include <QTcpSo…

详细介绍Python-pandas-DataFrame全部 *功能* 函数

Python-pandas-DataFrame全部 功能 函数 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是pandas的使用语法。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a;每个知识点…

香港科技大学广州|可持续能源与环境学域博士招生宣讲会—四川大学专场

香港科技大学广州&#xff5c;可持续能源与环境学域博士招生宣讲会—四川大学专场 时间&#xff1a;2025年5月8日&#xff08;星期四&#xff09;16:30开始 地点&#xff1a;四川大学基础教学楼A座504 宣讲嘉宾&#xff1a;肖殿勋 助理教授 一经录取&#xff0c;享全额奖学金…