Android外部存储权限变更下图片存储方案及代码适配问题
安卓存储适配方案(兼容KitKat及以上版本)
推荐存储位置选择
- 仅应用内部使用、不需要用户手动访问/卸载后无需保留:优先选择应用专属外部存储目录
该目录从Android 4.4(KitKat,API 19)开始访问无需申请任何存储权限,完全适配分区存储规则,不会受Android 10+的外部存储限制影响,应用卸载时会同步删除该目录下的文件,避免产生系统垃圾。 - 需要用户可在系统相册查看、卸载应用后仍需保留:选择公共Pictures目录下的应用专属子目录
你可以在系统公共的Pictures文件夹下创建单独以你的应用命名的子目录存储图片,用户可以直接在系统相册、文件管理器中找到这些图片,卸载应用后文件不会被删除。这种场景需要根据系统版本适配存储权限。
代码修改方案
首先替换原Vars.DataLoc的路径获取逻辑,以下是两种方案的实现代码:
// 方案1:使用应用专属外部存储目录(推荐,无需权限) public static string GetAppPrivateImageRootPath() { // 获取应用专属外部存储的Pictures目录,可按需替换为其他目录类型 var rootDir = Android.App.Application.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures); // 拼接Images子目录路径 string imageRootPath = Path.Combine(rootDir.AbsolutePath, "Images"); // 目录不存在则创建 if (!Directory.Exists(imageRootPath)) { Directory.CreateDirectory(imageRootPath); } return imageRootPath; } // 方案2:使用公共Pictures目录下的应用子目录 public static string GetPublicImageRootPath() { // 获取系统公共Pictures目录 var rootDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures); // 替换为你的应用名作为子目录名,避免和其他应用文件冲突 string imageRootPath = Path.Combine(rootDir.AbsolutePath, "你的应用名称/Images"); if (!Directory.Exists(imageRootPath)) { Directory.CreateDirectory(imageRootPath); } return imageRootPath; }
修改后的ImageAssetManager类示例:
public static class ImageAssetManager { public static Dictionary<string, Drawable> cache = new Dictionary<string, Drawable>(); // 缓存根路径,初始化一次即可,按需替换为GetPublicImageRootPath即可切换存储方案 private static readonly string _imageRootPath = GetAppPrivateImageRootPath(); public static Drawable Get(string url) { string imageurl = Path.Combine(_imageRootPath, url); if (!cache.ContainsKey(imageurl)) { Drawable drawable = Drawable.CreateFromPath(imageurl); cache.Add(imageurl, drawable); } return cache[imageurl]; } private static string GetAppPrivateImageRootPath() { var rootDir = Android.App.Application.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures); string imageRootPath = Path.Combine(rootDir.AbsolutePath, "Images"); if (!Directory.Exists(imageRootPath)) { Directory.CreateDirectory(imageRootPath); } return imageRootPath; } }
兼容注意事项
- 如果你选择公共目录方案,需要在
AndroidManifest.xml中添加对应权限:- API < 33:添加
WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限,运行时动态申请 - API >= 33:如果仅访问你自己应用写入的图片,不需要申请权限;如果需要读取其他应用存入公共目录的图片,需要申请
READ_MEDIA_IMAGES权限
- API < 33:添加
- 原有缓存逻辑可以按需优化:当前静态Dictionary缓存如果存储过多大图可能引发OOM,建议限制缓存上限,或者使用弱引用存储Drawable对象,内存不足时系统可自动回收。
内容的提问来源于stack exchange,提问作者Dan Dickerson
相关产品推荐
相关产品推荐

