Wann muss das Cache-Verzeichnis in Android gelöscht werden?

77

Ich habe eine Anwendung, die Bilder aus dem Internet anzeigt (Schaufenster für Designerarbeiten). Ich fange an, meinen Inhalt im internen Cache-Verzeichnis zwischenzuspeichern, aber der App-Inhalt kann eine Cache-Größe von ca. 150 MB haben. Und was Android Docs sagt:

Sie sollten die Cache-Dateien immer selbst verwalten und sich an eine angemessene Grenze des belegten Speicherplatzes halten, z. B. 1 MB. Wenn der Benutzer Ihre Anwendung deinstalliert, werden diese Dateien entfernt.

Also habe ich mir die Currents-App (Galaxy Nexus) angesehen und die Cache-Größe für die Anwendung beträgt 110 MB. Aber was seltsam ist, dass Anwendungen wie Google Currents und Google Maps den Inhalt in so genannten (USB-Speicherdaten) zwischenspeichern:

Geben Sie hier die Bildbeschreibung ein

Was sind diese 'USB-Speicherdaten', die die vorherige Anwendung verwendet? Und wenn Sie das Caching in Ihrer Anwendung implementieren, durchlaufen Sie alle Ihre Anwendungsdateien im Cache , um die Größe jedes Mal zu ermitteln, wenn Sie etwas einfügen und dann vergleichen und löschen müssen? Oder speichern Sie den Inhalt so lange zwischen, bis Android entscheidet, ob ein Anwendungs-Cache-Verzeichnis bereinigt werden soll?

Ich bin wirklich interessiert zu wissen, wie der Cache in Android abläuft oder was andere Anwendungen mit großen Inhalten für den Cache tun.

Jimmy
quelle
Ich nehme an, dass USB-Speicherdaten der in SD gespeicherte Cache sind. Meiner Meinung nach sollte die Größe des Caches vom Endbenutzer in der bevorzugten Aktivität ausgewählt werden, wobei die Dateien, auf die zuletzt zugegriffen wurde, gelöscht werden sollten, um das Limit beizubehalten.
Daniel Argüelles
5
In der Informatik gibt es nur zwei schwierige Dinge: Cache-Ungültigmachung und Benennung. - Phil Karlton
Msanford
1
@msanford Weißt du was schwieriger ist? Closing vim ...
varun

Antworten:

203

Bevor ich zu Ihrer Frage komme, finden Sie hier eine kurze Erläuterung der beiden Speichertypen:

Zwischenspeicher

Dies ist ein app-spezifisches Verzeichnis im Dateisystem. In diesem Verzeichnis sollen temporäre Daten gespeichert werden, die Ihre Anwendung möglicherweise zwischen den Sitzungen aufbewahren muss, die jedoch möglicherweise nicht unbedingt für immer gespeichert werden müssen. Normalerweise greifen Sie mit auf dieses Verzeichnis zu Context.getCacheDir(). Dies wird in Ihren App-Einstellungen als "Cache" angezeigt.

Dateien

Wie das Cache-Verzeichnis verfügt auch Ihre App über ein app-spezifisches Verzeichnis zum Speichern von Dateien. Dateien in diesem Verzeichnis bleiben bestehen, bis die App sie explizit löscht oder die App deinstalliert wird. Normalerweise greifen Sie mit auf dieses Verzeichnis zu Context.getFilesDir(). Dies kann auf dem App-Infobildschirm als verschiedene Dinge angezeigt werden, aber in Ihrem Screenshot ist dies "USB-Speicherdaten".

HINWEIS: Wenn Sie explizit auf externen Medien (normalerweise SD-Karte) platzieren möchten, können Sie diese verwenden Context.getExternalFilesDir(String type).

Der Unterschied

Beide Verzeichnisse sind nur für Ihre Anwendung spezifisch (andere Apps haben keinen Zugriff). Einer der Unterschiede zwischen dem Cache- und dem Dateiverzeichnis besteht darin, dass das System zunächst Ressourcen aus Ihrem Cache-Verzeichnis freigibt, wenn der Speicherplatz knapp wird. Das System löscht keine Daten aus dem Dateiverzeichnis. Ein weiterer Unterschied besteht darin, dass das Cache-Verzeichnis normalerweise manuell über den App-Info-Bildschirm gelöscht werden kann. Das Dateiverzeichnis kann dies normalerweise auch, aber das Löschen des Dateiverzeichnisses löscht auch das Cache-Verzeichnis.

Welches benutze ich?

Dies hängt davon ab, wie wichtig diese Daten im Vergleich zur Lebensdauer Ihrer App sind. Wenn Sie nur Daten für eine Sitzung benötigen und Zweifel haben, dass Sie diese Daten jemals wieder verwenden müssen, verwenden Sie sie auch nicht. Behalten Sie es einfach im Speicher, bis Sie es nicht mehr benötigen. Wenn Sie Sie vermuten , werden die Daten zwischen mehreren Sitzungen wiederverwendet werden müssen, aber Sie nicht haben eine harte Kopie zu halten, verwenden Sie das Cache - Verzeichnis. Wenn Sie diese Daten haben müssen, egal was passiert, oder wenn es sich um ziemlich große Daten handelt, die dauerhaft gespeichert werden müssen, verwenden Sie das Dateiverzeichnis. Hier sind einige Beispiele, die mir einfallen:

  • Cache - Eine kürzlich geöffnete E-Mail
    • Speichern Sie die Daten nach dem Öffnen im Cache. Wenn der Benutzer diese E-Mail erneut lesen möchte, wird sie sofort geladen, anstatt das Netzwerk erneut zu verwenden, um dieselben Daten abzurufen. Ich muss das nicht für immer behalten, da der Benutzer schließlich mit der E-Mail fertig sein wird.
  • Dateien - Ein Anhang, der aus einer E-Mail heruntergeladen wurde
    • Dies ist eine Aktion des Benutzers, der sagt: "Ich möchte diese Daten behalten, damit ich sie jederzeit wieder aufrufen kann." Legen Sie es daher im Dateiverzeichnis ab, da ich diese Datei erst löschen möchte, wenn der Benutzer sie löschen möchte.

Wann sollte ich das Cache-Verzeichnis löschen?

Aus den Context.getCacheDir()Javadocs:

Hinweis: Sie sollten sich nicht darauf verlassen, dass das System diese Dateien für Sie löscht. Sie sollten immer ein angemessenes Maximum haben, z. B. 1 MB, für den Speicherplatz, den Sie mit Cache-Dateien belegen, und diese Dateien bereinigen, wenn dieser Speicherplatz überschritten wird.

Es wird das Beispiel von 1 MB verwendet, aber das kann für Ihre App sinnvoll sein oder auch nicht. Unabhängig davon müssen Sie ein hartes Maximum festlegen. Der Grund dafür liegt einfach darin, eine verantwortungsvolle App zu entwerfen. Wann sollten Sie nachsehen? Ich würde empfehlen, jedes Mal zu überprüfen, wenn Sie etwas in das Cache-Verzeichnis stellen möchten. Hier ist ein sehr einfacher Cache-Manager:

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;
    }
}

Dies kann natürlich eine teure Operation sein, daher sollten Sie planen, einen Hintergrund-Thread zwischenzuspeichern.

Dies kann auch so kompliziert sein, wie Sie es brauchen. In meinem Beispiel gehe ich davon aus, dass alle zwischengespeicherten Dateien im Stammverzeichnis des Cache-Verzeichnisses abgelegt sind, sodass ich nicht nach potenziellen Unterverzeichnissen suche. Die Routine zum Löschen von Dateien kann auch komplexer werden, z. B. das Löschen von Dateien nach dem ältesten Zugriffsdatum.

Wenn Sie sich für das Zwischenspeichern von Daten entscheiden, sollten Sie immer berücksichtigen, dass Ihre zwischengespeicherten Daten nicht mehr vorhanden sind. Stellen Sie immer eine Routine bereit, um Daten auf externe Weise abzurufen, wenn Ihr Cache sie nicht gespeichert hat. Überprüfen Sie auch immer Ihren Cache, bevor Sie Daten extern abrufen. Der Zweck des Caches besteht darin, die Netzwerkaktivität und die langen Prozesse zu reduzieren und eine reaktionsschnelle Benutzeroberfläche in Ihrer App bereitzustellen. Also benutze es verantwortungsbewusst :)

Jason Robinson
quelle
Was ist, wenn ich eine App habe, die das weiche Speichern großer Dateien erfordert? Sollte ich nur den Cache wirklich hoch setzen und nicht aufgrund von Spezifikationen verantwortlich sein oder in filesDir speichern und einen Weg finden, die Datei von dort zu löschen?
Hipkiss
2
@hipkiss Die Größe des Caches wird je nach Anforderung zwischen den Apps unterschiedlich sein. Stellen Sie das Maximum auf das ein, was Ihrer Meinung nach für Ihre App angemessen ist.
Jason Robinson
@JasonRobinson Gibt es eine maximale Größenbeschränkung des Cache-Verzeichnisses oder kann eine App so viele Daten (z. B. 500 MB) enthalten, wie sie dort möchte?
Diffy
@Diffy Soweit ich weiß gibt es keine, aber ich weiß es nicht genau.
Jason Robinson
@ JasonRobinson Ich habe eine Frage zu stellen. Ich baue eine E-Library-App, die über den Webserver auf große PDF- oder Epub-Dateien zugreifen muss. Was soll ich Cache-Verzeichnis oder Dateien verwenden? Vielen Dank.
Ishwor Khanal
15

Der beste Weg, um den App-Cache zu löschen, wenn die Aktivität beendet ist, damit der Cache jedes Mal gelöscht wird, wenn eine neue Aktivität aufgerufen wird.

Fügen Sie diesen Code in onDestroy () ein, um den App-Cache zu löschen

@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();
}
Chirag
quelle
5
Nach dem onDestroy()Supercall? bist du srs
Yousha Aleayoub
1

Ich denke, die Idee hinter dem Cache ist, alles zu schreiben, was Sie wollen, und Android wird seine Größe verwalten, wenn es zu hoch wird.

Sie sollten bedenken, dass Sie Dateien in den Cache schreiben können, aber immer prüfen, ob die Datei noch gespeichert ist, wenn Sie versuchen, darauf zuzugreifen. Und lassen Sie Android den Cache verwalten.

Marcio Covre
quelle
1

Abhängig von der Art der Anwendung:

  • Einige Anwendungen verwenden nur einzelne Sitzungen und müssen sich keine Daten merken, sodass Sie den Cache jederzeit löschen können (einige Apps tun dies sogar automatisch in ihrer OnStop-Aktivität).
  • Die meisten Anwendungen behalten Ihre Daten, weil sie sich an Ihre Einstellungen, das Konto, mit dem Sie sich angemeldet haben, usw. erinnern. In diesem Fall ist es am besten, den Cache nur zu leeren, wenn Sie die Anwendung nicht häufig verwenden.

Ebenfalls:

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) :

AFAIK, USB-Speicherdaten haben eine andere Verwendung als der Cache: Der Speicher dient zum Speichern programmspezifischer Informationen (wie Karten für eine GPS-App), der Cache zum Speichern benutzerspezifischer Informationen (wie Anmeldungen).

Im Fall von Google Maps: Ich gehe davon aus, dass sie Kartendaten im USB-Speicher speichern und Ihre Einstellungen und den Suchverlauf im Cache speichern ==> Kartendaten sind anwendungsspezifisch, Einstellungen und Suchverlauf sind benutzerspezifisch

Andreas
quelle