web-dev-qa-db-ja.com

Androidでキャッシュディレクトリをクリアするタイミング

インターネットからの写真を表示するアプリケーションがあります(デザイナーの仕事のショーケース)。内部キャッシュディレクトリでコンテンツのキャッシュを開始しますが、アプリコンテンツのキャッシュサイズは約150 MBになる場合があります。そして、Android docs says:

キャッシュファイルは常に自分で管理し、1MBなどの消費されるスペースの合理的な制限内にとどめる必要があります。ユーザーがアプリケーションをアンインストールすると、これらのファイルは削除されます。

そこで、Currentsアプリ(Galaxy Nexus)を見てみると、アプリケーションのキャッシュサイズは110 MBです。しかし奇妙なのは、Google CurrentsやGoogle Mapsのようなアプリケーションが(USB Storage Data)と呼ばれるものにコンテンツをキャッシュすることです:

enter image description here

それで、以前のアプリケーションが使用するこの「USBストレージデータ」とは何ですか。また、アプリケーションにキャッシングを実装する場合、キャッシュにあるすべてのアプリケーションファイル をループしますか 、何かを挿入する必要があるたびにサイズを取得します。比較してクリアしますか?または、Android=がアプリケーションキャッシュディレクトリを削除する時間を決定するまで、コンテンツをキャッシュし続けますか?

Androidでキャッシュを管理するフローとは何か、または少なくとも他のアプリケーションがキャッシュする大量のコンテンツをどのように処理するかを知りたいと思っています。

76
Jimmy

質問に答える前に、2つのストレージタイプについて簡単に説明します。

キャッシュ

これは、ファイルシステム上のアプリ固有のディレクトリです。このディレクトリの目的は、アプリケーションがセッション間で保持する必要があるかもしれない一時データを保存することですが、それらを永久に保持するために不可欠ではない場合があります。通常、このディレクトリには Context.getCacheDir() でアクセスします。これは、アプリの設定に「キャッシュ」として表示されます。

ファイル

キャッシュディレクトリと同様に、アプリにはファイルを保持するためのアプリ固有のディレクトリもあります。このディレクトリ内のファイルは、アプリが明示的に削除するか、アプリがアンインストールされるまで存在します。通常、このディレクトリには Context.getFilesDir() でアクセスします。これはアプリの情報画面にさまざまなものとして表示されますが、スクリーンショットでは「USBストレージデータ」です。

注:外部メディア(通常はSDカード)に明示的に配置する場合は、 Context.getExternalFilesDir(String type)

違い

両方のディレクトリは、アプリケーションのみに固有です(他のアプリにはアクセスできません)。キャッシュディレクトリとファイルディレクトリの違いの1つは、システムのストレージが少なくなった場合、最初にリソースを解放するのはキャッシュディレクトリからであることです。システムは、ファイルディレクトリからデータを消去しません。別の違いは、キャッシュディレクトリは通常、アプリ情報画面から手動でクリアできることです。通常、ファイルディレクトリも同様ですが、ファイルディレクトリをクリアするとキャッシュディレクトリもクリアされます。

どちらを使用しますか?

それは、データがアプリの存続期間と比較してどれだけ重要かによって異なります。 1つのセッションのデータのみが必要で、そのデータを再び使用する必要があると思わない場合は、どちらも使用しないでください。不要になるまでメモリに保存してください。複数のセッション間でデータを再利用する必要があると思われるが、ハードコピーを保持するためにhaveを使用しない場合は、キャッシュディレクトリを使用します。何があってもこのデータが必要な場合、または永続ストレージを必要とするかなり大きなデータの場合は、filesディレクトリを使用します。ここに私が考えることができるいくつかの例があります:

  • キャッシュ-最近開いたメール
    • 開いたら、データをキャッシュして、ユーザーがその電子メールを再度読みたいときに、同じデータを取得するために再びネットワークを使用するのではなく、即座にロードします。最終的にユーザーが電子メールで終了するので、これを永久に保持する必要はありません。
  • ファイル-メールからダウンロードした添付ファイル
    • これは、「必要なときにいつでも元に戻すことができるように、このデータを保持したい」というユーザーによるアクションです。したがって、ユーザーが削除するまでこのファイルを削除したくないので、ファイルディレクトリに配置します。

キャッシュディレクトリをクリアする必要があるのはいつですか?

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

もちろん、これは高価な操作になる可能性があるため、バックグラウンドスレッドでのキャッシュを計画する必要があります。

また、必要なだけ複雑になります。私の例では、すべてのキャッシュファイルがキャッシュディレクトリのルートに配置されると想定しているため、潜在的なサブディレクトリをチェックしません。ファイルを削除するためのルーチンは、最も古いアクセス日までにファイルを削除するなど、より洗練されたものにすることもできます。

データをキャッシュすることを決定する際に留意すべきことの1つは、キャッシュされたデータがもはや存在しない場合について常に計画する必要があるということです。キャッシュに保存されていないデータを外部手段で取得するためのルーチンを常に用意してください。同様に、外部からデータを取得する前に、常にキャッシュを確認してください。キャッシュの目的は、ネットワークアクティビティ、長いプロセスを削減し、アプリでレスポンシブUIを提供することです。責任を持って使用してください:)

189
Jason Robinson

アクティビティが終了したときにアプリのキャッシュをクリアして、新しいアクティビティが呼び出されるたびにキャッシュがクリアされるようにする最善の方法です。

アプリのキャッシュをクリアするには、このコードを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();
}
15
Chirag

アプリケーションのタイプに依存します。

  • 一部のアプリケーションは単一のセッションのみを使用し、データを記憶する必要がないため、必要なときにキャッシュをクリアできます(一部のアプリケーションは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ストレージに保存し、設定と検索履歴をキャッシュに保存する==>地図データはアプリケーション固有、設定と検索履歴はユーザー固有

1
Andreas

キャッシュの背後にあるアイデアは、必要なものをすべて書き込むことであり、Androidはサイズが大きくなりすぎるとサイズを管理します。

キャッシュにファイルを書き込むことはできますが、アクセスしようとするときは常にファイルが保存されているかどうかを常に確認する必要があります。そして、Androidキャッシュを管理します。

1
Marcio Covre

ドキュメントによると、システムは デバイスの内部ストレージが少ない の場合にキャッシュをクリアします。 API8から getExternalCacheDir() メソッドを読んでいるので、約150MBのデータを取得できるので便利ですが、外部キャッシュの欠点は、取得した場合にキャッシュディレクトリを自分で消去する必要があることです大きすぎる。

0
Kowlown