从网络到缓存:在Android中高效管理图片加载

文章目录

首先我们需要在配置AndroidManifest.xml里面添加

xml 复制代码
<uses-permission android:name="android.permission.INTERNET" />

在Android应用中实现图片缓存和下载

在现代移动应用开发中,用户体验至关重要,特别是在图像加载方面。为了提高应用的响应速度和减少网络流量,我们通常采用缓存机制来存储下载的图片。本文将介绍如何在Android中实现一个简单的图片缓存加载器,允许从网络下载图片并缓存到本地。

项目结构

我们将构建一个名为 ImageCacheLoader 的类,该类负责从URL加载图片,并首先检查本地缓存。如果缓存不存在,则从网络下载图片。

使用
java 复制代码
package com.example.dowhttppic;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import android.os.Bundle;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private ImageCacheLoader imageCacheLoader;

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

        imageView = findViewById(R.id.imageView);

        // 初始化 ImageCacheLoader
        imageCacheLoader = new ImageCacheLoader(this);

        // 加载图片
        String imageUrl = "图片链接";
        imageCacheLoader.loadImage(imageUrl, imageView);
    }
}

代码解析

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

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.widget.ImageView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class ImageCacheLoader {

    private Context context;
    private Handler handler = new Handler(); // 用于处理UI线程更新

    // 构造函数,接收上下文
    public ImageCacheLoader(Context context) {
        this.context = context;
    }

    // 公共方法:加载图片,首先从缓存读取,如果没有则通过网络下载
    public void loadImage(final String url, final ImageView imageView) {
        // 获取缓存目录
        File cacheDir = context.getCacheDir();
        String fileName = getFileNameFromUrl(url);
        final File imageFile = new File(cacheDir, fileName);

        // 如果本地有缓存,直接加载本地图片
        if (imageFile.exists()) {
            Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
            imageView.setImageBitmap(bitmap);
        } else {
            // 启动线程下载图片并缓存
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Bitmap bitmap = downloadImage(url);
                    if (bitmap != null) {
                        saveImageToCache(imageFile, bitmap);

                        // 更新UI,需在主线程中执行
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                imageView.setImageBitmap(bitmap);
                            }
                        });
                    } else {
                        // 超时或下载失败时显示默认图片
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                imageView.setImageResource(R.drawable.no_image_dow_http);
                            }
                        });
                    }
                }
            }).start();
        }
    }

    // 从网络下载图片,添加超时机制
    private Bitmap downloadImage(String urlString) {
        Bitmap bitmap = null;
        try {
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5000); // 设置连接超时为5秒
            connection.setReadTimeout(5000); // 设置读取超时为5秒
            connection.connect();
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = connection.getInputStream();
                bitmap = BitmapFactory.decodeStream(inputStream);
                inputStream.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    // 将下载的图片保存到本地缓存
    private void saveImageToCache(File imageFile, Bitmap bitmap) {
        try {
            OutputStream outputStream = new FileOutputStream(imageFile);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 根据URL提取文件名
    private String getFileNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }
}

关键功能解析

1. 图片加载方法

loadImage 方法是该类的核心,它负责加载指定URL的图片。首先,它尝试从本地缓存读取图片,如果缓存存在,则直接使用缓存的图片;如果不存在,则启动一个新线程下载图片。

java 复制代码
public void loadImage(final String url, final ImageView imageView) {
    File cacheDir = context.getCacheDir();
    String fileName = getFileNameFromUrl(url);
    final File imageFile = new File(cacheDir, fileName);

    if (imageFile.exists()) {
        Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
        imageView.setImageBitmap(bitmap);
    } else {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if (bitmap != null) {
                    saveImageToCache(imageFile, bitmap);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    });
                } else {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageResource(R.drawable.no_image_dow_http);
                        }
                    });
                }
            }
        }).start();
    }
}
2. 下载图片

downloadImage 方法使用 HttpURLConnection 从给定URL下载图片。它设置了连接和读取的超时,以避免长时间等待。

java 复制代码
private Bitmap downloadImage(String urlString) {
    Bitmap bitmap = null;
    try {
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.connect();
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream inputStream = connection.getInputStream();
            bitmap = BitmapFactory.decodeStream(inputStream);
            inputStream.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return bitmap;
}
3. 保存图片到缓存

saveImageToCache 方法将下载的图片以PNG格式保存到应用的缓存目录中。

java 复制代码
private void saveImageToCache(File imageFile, Bitmap bitmap) {
    try {
        OutputStream outputStream = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        outputStream.flush();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
4. 文件名提取

getFileNameFromUrl 方法从图片URL中提取文件名,以便在缓存中使用。

java 复制代码
private String getFileNameFromUrl(String url) {
    return url.substring(url.lastIndexOf("/") + 1);
}

总结

通过实现 ImageCacheLoader 类,我们成功地创建了一个简单的图片加载和缓存机制。这种方法不仅减少了网络流量,还提高了应用的响应速度和用户体验。在实际应用中,你可以根据需要进一步扩展该类,例如添加图片加载动画、处理更多的错误情况,或是实现更复杂的缓存策略。

相关推荐
只因在人海中多看了你一眼1 小时前
分布式缓存 + 数据存储 + 消息队列知识体系
分布式·缓存
速盾cdn2 小时前
速盾:CDN是否支持屏蔽IP?
网络·网络协议·tcp/ip
yaoxin5211232 小时前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin2 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
Dlwyz2 小时前
redis-击穿、穿透、雪崩
数据库·redis·缓存
PersistJiao3 小时前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark
黑客Ash6 小时前
【D01】网络安全概论
网络·安全·web安全·php
->yjy6 小时前
计算机网络(第一章)
网络·计算机网络·php
Oak Zhang7 小时前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存
摘星星ʕ•̫͡•ʔ7 小时前
计算机网络 第三章:数据链路层(关于争用期的超详细内容)
网络·计算机网络