目錄
第十一章: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();
? 實戰練習建議
-
實現一個圖文混排的 RecyclerView 列表,動態加載網絡圖片
-
使用 Glide 加載 GIF 動圖
-
用 GlideTransform 實現頭像圓形 + 外邊框效果
-
編寫工具類
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;}
}
總結
- 圖文混排:通過?
RecyclerView
?展示圖片和文字。 - 動態加載網絡圖片:使用?
Glide
?加載普通圖片和 GIF 動圖。 - 圓形頭像 + 邊框:通過自定義?
CircleBorderTransform
?實現。 - 工具類封裝:
GlideUtils
?封裝了通用的圖片加載邏輯。