android - 何时清除 Android 中的缓存目录?

我有一个显示来自互联网的图片的应用程序(展示设计师作品)。我开始在内部缓存目录中缓存我的内容,但应用程序内容可能需要大约 150 MB 的缓存大小。什么 android 文档说:

You should always maintain the cache files yourself and stay within a reasonable limit of space consumed, such as 1MB. When the user uninstalls your application, these files are removed.



所以我查看了 Currents 应用程序(Galaxy Nexus),该应用程序的缓存大小为 110 MB。但奇怪的是,像 Google Currents 和 Google Maps 这样的应用程序将内容缓存在一个叫做 (USB Storage Data) 的东西中:



那么之前的应用程序使用的这个“USB 存储数据”是什么?如果你在你的应用程序中实现缓存,你是否循环遍历所有 your application files in cache每次需要插入东西时获取大小,然后比较并清除它?或者你一直缓存内容直到 Android 决定它的时间来清理一些应用程序缓存目录?

我真的很想知道在 Android 中管理缓存的流程是什么,或者至少其他应用程序如何处理要缓存的大量内容。

最佳答案

在我回答您的问题之前,以下是对两种存储类型的简要说明:

缓存

这是文件系统上特定于应用程序的目录。此目录的目的是存储您的应用程序可能需要在 session 之间保留的临时数据,但对于永久保留它们可能并不重要。您通常使用 Context.getCacheDir() 访问此目录.这将在您的应用设置中显示为“缓存”。

文件

与缓存目录一样,您的应用程序也有一个用于保存文件的特定于应用程序的目录。此目录中的文件将一直存在,直到应用程序明确删除它们或卸载应用程序。您通常使用 Context.getFilesDir() 访问此目录.这可以在应用程序信息屏幕上显示为各种内容,但在您的屏幕截图中,这是“USB 存储数据”。

注意:如果你想明确地放置在外部媒体(通常是 SD 卡)上,你可以使用 Context.getExternalFilesDir(String type) .

差异

这两个目录都特定于您的应用程序(其他应用程序无权访问)。缓存目录和文件目录之间的一个区别是,如果系统存储空间不足,它首先要从缓存目录中释放资源。系统不会清除文件目录中的任何数据。另一个区别是缓存目录通常可以从应用程序信息屏幕手动清除。 files 目录通常也可以,但清除 files 目录也会清除缓存目录。

我使用哪一种?

这取决于该数据与您的应用程序的生命周期相比的重要性。如果您只需要一个 session 的数据并且您怀疑您是否需要再次使用该数据,那么不要使用任何一个。只需将其保存在内存中,直到您不需要它为止。如果您怀疑需要在多个 session 之间重用数据,但又不必保留硬拷贝,请使用缓存目录。如果您无论如何都必须拥有这些数据,或者是需要持久存储的相当大的数据,请使用 files 目录。以下是我能想到的一些例子:

  • 缓存 - 最近打开的电子邮件
  • 打开后,缓存数据,以便当用户想要再次阅读该电子邮件时,它会立即加载,而不是再次使用网络来检索相同的数据。我不需要永远保留它,因为最终用户将完成电子邮件。
  • 文件 - 从电子邮件下载的附件
  • 这是用户的操作,他说“我想保留此数据,以便我可以在需要时将其拉回”。因此,将它放在 files 目录中,因为我不想删除这个文件,直到用户想要删除它。

  • 我应该什么时候清除缓存目录?

    来自 Context.getCacheDir()文档:

    Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space.



    它使用 1 MB 的示例,但这对您的应用程序可能合理,也可能不合理。无论如何,您需要设置一个硬最大值。这样做的原因归结为设计一个负责任的应用程序。那么什么时候应该检查呢?我建议您每次要在缓存目录中放入内容时进行检查。这是一个非常简单的缓存管理器:
    public class CacheManager {
    
        private static final long MAX_SIZE = 5242880L; // 5MB
    
        private CacheManager() {
    
        }
    
        public static void cacheData(Context context, byte[] data, String name) throws IOException {
    
            File cacheDir = context.getCacheDir();
            long size = getDirSize(cacheDir);
            long newSize = data.length + size;
    
            if (newSize > MAX_SIZE) {
                cleanDir(cacheDir, newSize - MAX_SIZE);
            }
    
            File file = new File(cacheDir, name);
            FileOutputStream os = new FileOutputStream(file);
            try {
                os.write(data);
            }
            finally {
                os.flush();
                os.close();
            }
        }
    
        public static byte[] retrieveData(Context context, String name) throws IOException {
    
            File cacheDir = context.getCacheDir();
            File file = new File(cacheDir, name);
    
            if (!file.exists()) {
                // Data doesn't exist
                return null;
            }
    
            byte[] data = new byte[(int) file.length()];
            FileInputStream is = new FileInputStream(file);
            try {
                is.read(data);
            }
            finally {
                is.close();
            }
    
            return data;
        }
    
        private static void cleanDir(File dir, long bytes) {
    
            long bytesDeleted = 0;
            File[] files = dir.listFiles();
    
            for (File file : files) {
                bytesDeleted += file.length();
                file.delete();
    
                if (bytesDeleted >= bytes) {
                    break;
                }
            }
        }
    
        private static long getDirSize(File dir) {
    
            long size = 0;
            File[] files = dir.listFiles();
    
            for (File file : files) {
                if (file.isFile()) {
                    size += file.length();
                }
            }
    
            return size;
        }
    }
    

    当然,这可能是一项昂贵的操作,因此您应该计划在后台线程上缓存。

    此外,这可能与您需要的一样复杂。在我的示例中,我假设所有缓存文件都放在缓存目录的根目录下,因此我不检查潜在的子目录。删除文件的例程也可以变得更加复杂,例如按最旧的访问日期删除文件。

    在决定缓存数据时要记住的一件事是,您需要始终计划缓存数据不再存在的情况。当您的缓存中没有数据时,始终有一个程序来通过外部方式检索数据。同样,在从外部检索数据之前,请始终检查您的缓存。缓存的目的是减少网络 Activity 、长时间的进程,并在您的应用程序中提供响应式 UI。所以负责任地使用它:)

    https://stackoverflow.com/questions/9942560/

    相关文章:

    android - 如何在没有硬件加速的情况下在 Windows 8 上为 API 21 和 19

    android - NoSuchFieldError : No static field listV

    android - transformClassesAndResourcesWithProguard

    android - 如何将 Activity 带到前台(堆栈顶部)?

    android - 如何使用它自己的操作按钮关闭 Snackbar?

    android - Kotlin 错误 : Could not find org. jetbrain

    android - 可以在 Android 应用程序中以编程方式打开 Spinner 吗?

    android - 无法从浏览器下载安装 APK

    android - 如何遍历共享偏好的所有键?

    android - 如何使用 Android Studio 查看共享首选项文件?