在Android中何时清除缓存目录?

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

您应该始终自己维护缓存文件,并保持在合理的空间限制内,例如1MB。用户卸载您的应用程序时,这些文件将被删除。

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

enter image description here

那么前面的应用程序使用的'USB存储数据'是什么?如果您在应用程序中实现缓存,是否会循环遍历所有缓存中的应用程序文件以获取每次需要插入内容时的大小,然后进行比较和清除?还是一直缓存内容,直到Android决定清理一些应用程序缓存目录?
我真的很想知道在Android中管理缓存的流程,或者至少其他应用程序是如何处理大量缓存内容的。

我认为USB存储数据是保存在SD卡中的缓存。在我看来,缓存的大小应该由最终用户在首选项活动中选择,并删除最后访问的文件以保持限制。 - Daniel Argüelles
5
计算机科学中只有两个难点:缓存失效和命名事物。-- Phil Karlton - msanford
1
@msanford 你知道什么更难吗?关闭vim... - varun
5个回答

213
在回答您的问题之前,这里简要介绍一下两种存储类型:
缓存
这是文件系统上特定于应用程序的目录。该目录旨在存储应用程序可能需要在会话之间保留的临时数据,但不一定需要永久保存。通常使用Context.getCacheDir()访问此目录。这将显示为“缓存”在您的应用设置中。
文件
与缓存目录类似,您的应用还具有特定于应用程序的目录以保存文件。在此目录中的文件将存在,直到应用显式删除它们或卸载应用为止。通常使用Context.getFilesDir()访问此目录。这可以显示为应用信息屏幕上的各种内容,但在您的截图中,它是“USB存储数据”。
注意:如果要明确放置在外部媒体(通常是SD卡)上,则可以使用Context.getExternalFilesDir(String type)
区别
两个目录都仅适用于您的应用程序(其他应用程序无法访问)。缓存目录和文件目录之间的区别之一是,如果系统存储空间不足,则首先释放资源的地方是您的缓存目录。系统不会清除文件目录中的任何数据。另一个区别是,可以从应用程序信息屏幕手动清除缓存目录。文件目录通常也可以清除,但清除文件目录也将清除缓存目录。
我该使用哪个?
这取决于数据与应用程序生命周期的重要性。如果您只需要在一个会话中使用数据,并且您怀疑永远不需要再次使用该数据,则不要使用任何一个。只需将其保存在内存中,直到不再需要为止。如果您怀疑需要在多个会话之间重复使用数据,但不必保留硬副本,请使用缓存目录。如果您必须无论如何都要使用此数据,或者它是需要持久存储的较大数据,请使用文件目录。以下是我能想到的一些示例:
  • 缓存 - 最近打开的电子邮件
    • 一旦打开,缓存数据,以便用户再次阅读该电子邮件时,可以立即加载,而无需再次使用网络检索相同的数据。我不需要永久保留这些数据,因为最终用户将完成电子邮件。
  • 文件 - 从电子邮件下载的附件
    • 这是用户执行的操作,表示“我想保留这些数据,以便在需要时可以重新调用它。”因此,将其放入文件目录中,因为我永远不希望删除此文件,除非用户要求删除。

何时清除缓存目录?

来自Context.getCacheDir() javadocs:

注意:您不应该依赖系统为您删除这些文件;您应该始终具有合理的最大值,例如1 MB,用于消耗缓存文件的空间,并在超过该空间时修剪这些文件。

它使用了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;
    }
}

当然,这可能是一个昂贵的操作,所以你应该计划在后台线程上缓存。此外,这可以变得像你需要的那样复杂。在我的例子中,我假设所有缓存文件都放置在缓存目录的根目录下,因此我没有检查潜在的子目录。删除文件的例程也可以变得更加复杂,例如按最早访问日期删除文件。决定缓存数据时需要记住的一件事情是,你需要始终为缓存数据不存在的情况做好准备。当你的缓存没有存储数据时,请始终准备一种通过外部手段检索数据的例程。同样,在从外部检索数据之前,请始终检查你的缓存。缓存的目的是减少网络活动、长时间处理并在您的应用程序中提供响应的UI。因此,请负责任地使用它 :)

1
如果我有一个需要对大文件进行软存储的应用程序,该怎么办?我是应该将缓存设置得非常高并且不负责因规格而存储在 filesDir 中,并找到一种删除文件的方法吗? - hipkiss
2
@hipkiss 缓存的大小将根据应用程序的需求而有所不同。请根据您的应用程序需求,将最大值设置为您认为合理的数值。 - Jason Robinson
@JasonRobinson 我有一个问题要问。我正在构建一个电子图书馆应用程序,需要从Web服务器访问大型PDF或EPUB文件。我应该使用缓存目录还是文件?谢谢。 - Ishwor Khanal
您可以按照日期对文件进行排序,以删除旧文件。以下是用于对文件进行排序的链接: https://dev59.com/H2015IYBdhLWcg3w6QHA?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa - Amir Ziarati
@MichaelGarner:不,这两个目录之间没有性能差异。虽然这是一个旧答案,但肯定有比这更简单和更清晰的解决方案。我建议找到一种更现代的方法。 - Jason Robinson
显示剩余3条评论

16

我认为在Activity结束时清除应用程序缓存是最好的方式,这样每次新的Activity调用时都会清除缓存。

将以下代码放入onDestroy()中以清除应用程序缓存。

@Override
protected void onDestroy() {

    super.onDestroy();
    try {
        trimCache(this);
       // Toast.makeText(this,"onDestroy " ,Toast.LENGTH_LONG).show();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void trimCache(Context context) {
    try {
       File dir = context.getCacheDir();
       if (dir != null && dir.isDirectory()) {
          deleteDir(dir);
       }
    } catch (Exception e) {
       // TODO: handle exception
    }
 }

public static boolean deleteDir(File dir) {
    if (dir != null && dir.isDirectory()) {
       String[] children = dir.list();
       for (int i = 0; i < children.length; i++) {
          boolean success = deleteDir(new File(dir, children[i]));
          if (!success) {
             return false;
          }
       }
    }
    // The directory is now empty so delete it
    return dir.delete();
}

7
هœ¨è°ƒç”¨onDestroy()çڑ„superو–¹و³•ن¹‹هگژï¼ںن½ وک¯è®¤çœںçڑ„هگ—ï¼ں - Yousha Aleayoub

1

我认为缓存背后的想法是可以将任何你想要的东西写入其中,如果它变得太大,Android会管理其大小。

你应该记住,你可以将文件写入缓存,但在尝试访问它时始终检查文件是否仍然保存。并让Android管理缓存。


1
根据文档,系统将在 设备内部存储空间不足 时清除缓存。自 API8 以来,您有 getExternalCacheDir() 方法,我认为它很有用,因为我读到您可以拥有大约150MB的数据,但外部缓存的缺点是如果它变得太大,您将不得不自己清理缓存目录。

1

这取决于应用程序的类型:

  • 一些应用程序仅使用单个会话,不需要记住任何数据,因此您可以在需要时清除缓存(有些应用程序甚至会在其onStop活动中自动执行此操作)
  • 大多数应用程序保留您的数据,因为它们记住您的设置、您用于登录的帐户等。在这种情况下,最好只在您很少使用该应用程序时清除缓存。

另外:

So i took a look at Chrome app (Galaxy Nexus) and the cache size for the application is 110 MB. But what wired is that applications like Google current & Google maps cache the content in something called (USB Storage Data) :

据我所知,USB 存储数据与缓存有不同的用途:存储是用于存储程序特定信息(例如 GPS 应用程序中的地图),而缓存用于存储用户特定信息(例如登录信息)。
以 Google 地图为例:我认为他们将地图数据存储在 USB 存储器中,并将您的设置和搜索历史记录保存在缓存中 ==> 地图数据是应用程序特定的,设置和搜索历史记录是用户特定的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接