上一篇
安卓存储图片视频缓存
- 行业动态
- 2025-04-23
- 2411
安卓图片视频缓存存内部/外部存储,内部可自动清理,外部需权限,注意 存储空间
安卓存储图片视频缓存详解
存储方式分类
安卓中存储图片/视频的主要方式分为以下几类:
存储类型 | 特点 | 适用场景 |
---|---|---|
内部存储 | 私有目录(/data/data/包名/ )无需申请权限 卸载应用时自动清除 | 敏感数据、小文件长期存储 |
外部存储 | 公有目录(/sdcard/ 或 Android/data/包名/ )需申请 WRITE_EXTERNAL_STORAGE 权限(Android 10以下)Android 10+ 需使用作用域存储(Scoped Storage) | 大文件、用户生成内容(需用户授权) |
内存缓存 | 基于LruCache 生命周期随应用/Activity 速度快但容量有限 | 频繁访问的小图片(如列表缩略图) |
数据库存储 | 使用SQLite或Room 适合结构化数据(如图片URL+元信息) | 需要关联查询的场景 |
第三方库缓存 | 如Glide、Picasso、ExoPlayer 自动管理内存/磁盘缓存 | 快速集成复杂缓存逻辑 |
缓存策略实现
内存缓存(LruCache)
// 初始化内存缓存(最多缓存100张图片) int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int cacheSize = maxMemory / 8; // 占用内存的1/8 LruCache<String, Bitmap> memoryCache = new LruCache<>(cacheSize); // 设置缓存逻辑 memoryCache.setFetchHandler(new Runnable() { @Override public void run() { // 可在此处加载磁盘缓存或网络数据 } });
磁盘缓存(Internal/External)
// 写入内部存储 File cacheDir = context.getCacheDir(); // 等效于 context.getExternalFilesDir(null) FileOutputStream fos = new FileOutputStream(new File(cacheDir, "image.jpg")); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); // 写入外部存储(需权限) File externalFile = new File(context.getExternalFilesDir(null), "video.mp4"); FileOutputStream externalFos = new FileOutputStream(externalFile); externalFos.write(videoBytes);
视频缓存优化
- 分段缓存:边下载边播放(如ExoPlayer的
CacheDataSource
) - 缓存清理:按LRU策略删除旧文件(可通过
File.lastModified()
判断) - 示例(ExoPlayer缓存配置):
// 设置缓存目录和最大大小(50MB) SimpleCache cache = new SimpleCache(context.getCacheDir(), new LeastRecentlyUsedCacheEvictor(50 1024 1024)); ExoPlayer player = new ExoPlayer.Builder(context) .build(); player.setMediaSource(new CacheDataSource.Factory(cache).createDataSource(mediaUri));
关键注意事项
权限管理:
- Android 6.0+:动态申请
WRITE_EXTERNAL_STORAGE
- Android 10+:使用
Scoped Storage
,通过ACTION_OPEN_DOCUMENT_TREE
获取持久化目录权限 - Android 11+:外部存储默认不可访问,需声明
manage_external_storage
权限(谨慎使用)
- Android 6.0+:动态申请
存储空间限制:
- 监控缓存大小,超过阈值时清理(如删除最久未使用的文件)
- 使用
StatFs
获取剩余空间:File cacheDir = context.getCacheDir(); StatFs statFs = new StatFs(cacheDir.getPath()); long availableSpace = (long) statFs.getBlockSize() statFs.getAvailableBlocks();
兼容性处理:
- 区分Android版本动态选择存储策略(如作用域存储适配)
- 避免直接使用
Environment.getExternalStorageDirectory()
(已被弃用)
常见问题与解决方案
问题1:缓存图片/视频后出现重复加载
- 原因:未对缓存文件进行哈希校验(如MD5),导致相同资源多次存储。
- 解决:
String fileName = "image_" + MD5(url) + ".jpg"; // 计算URL的MD5值作为文件名
问题2:大视频文件缓存导致OOM
- 原因:直接将视频文件读入内存处理。
- 解决:
- 使用流式处理(
InputStream
) - 分块写入磁盘缓存(如每次写入1MB)
- 示例:
FileOutputStream fos = new FileOutputStream(videoFile, true); // 追加模式 byte[] buffer = new byte[1024 1024]; // 1MB缓冲区 int len; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); }
- 使用流式处理(
相关问题与解答
Q1:如何自动清理过期的缓存文件?
- A1:可通过记录文件的创建时间或访问时间,定期扫描并删除超过指定时长的文件。
File[] files = cacheDir.listFiles(); long currentTime = System.currentTimeMillis(); for (File file : files) { if (currentTime file.lastModified() > 7 24 60 60 1000) { // 超过7天 file.delete(); } }
Q2:如何在低内存设备上优化图片缓存?
- A2:
- 降低图片质量(如压缩至80%再存储)
- 优先使用内存缓存,减少磁盘IO
- 对图片进行缩放(如按屏幕密度生成不同尺寸的缓存)
- 使用WebP格式替代JPEG/PNG(需系统支持)