冗長なダウンロードを回避する

アプリのユーザーの多くは、インターネットに断続的にアクセスしているか、デバイスにダウンロードできる情報の量に制限があります。アプリでダウンロードする必要があるデータの量を減らすことで、ユーザーがアプリをより頻繁に操作するように促すことができます。

ダウンロードを削減する最も基本的な方法は、必要なものだけをダウンロードすることです。データに関しては、これは REST API を実装することを意味します。この API では、最終更新日時などのパラメータを使用して、返されるデータを制限するクエリ条件を指定できます。

同様に、画像をダウンロードする場合は、フルサイズの画像をダウンロードしてクライアント側で削減してもらうのではなく、サーバー側で画像のサイズを削減することをおすすめします。

ファイルをローカルにキャッシュする

もう 1 つの重要な手法は、重複データのダウンロードを回避することです。キャッシュを使用すると、同じデータを繰り返しダウンロードする可能性を減らすことができます。アプリのデータとリソースをキャッシュすることにより、アプリが参照する必要がある情報のローカルコピーを作成します。アプリが同じ情報に短期間に何度もアクセスする必要がある場合、キャッシュにダウンロードする必要があるのは 1 回だけです。

ダウンロードするデータの合計量を減らすには、できるだけ積極的にキャッシュすることが重要です。合理的に可能な限り、静的リソース(フルサイズの画像などのオンデマンド ダウンロードを含む)をキャッシュするようにしてください。オンデマンド キャッシュを定期的にフラッシュしてサイズを管理できるように、オンデマンド リソースは個別に保存する必要があります。

キャッシュによってアプリに古いデータが表示されないようにするには、HTTP 応答ヘッダーから、要求されたコンテンツの最終更新日時と有効期限を抽出してください。これにより、関連付けられたコンテンツを更新するタイミングを決定できます。

Kotlin

    val conn: HttpsURLConnection = url.openConnection() as HttpsURLConnection
    val currentTime: Long = System.currentTimeMillis()
    val expires: Long = conn.getHeaderFieldDate("Expires", currentTime)
    val lastModified: Long = conn.getHeaderFieldDate("Last-Modified", currentTime)
    if (lastModified < lastUpdateTime) {
        // Skip update
    } else {
        // Parse update
        lastUpdateTime = lastModified
    }
    

Java

    // url represents the website containing the content to place into the cache.
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

    long currentTime = System.currentTimeMillis();
    long expires = conn.getHeaderFieldDate("Expires", currentTime);
    long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);

    // lastUpdateTime represents when the cache was last updated.
    if (lastModified < lastUpdateTime) {
        // Skip update
    } else {
        // Parse update
        lastUpdateTime = lastModified;
    }
    

この手法を使用すると、動的なコンテンツを効果的にキャッシュしながら、アプリケーションに古い情報が表示されないようにすることもできます。

機密情報でないデータは、Context#getExternalCacheDir() を介して取得した、管理対象外の外部キャッシュ ディレクトリにキャッシュできます。

または、Context#getCacheDir() を介して取得した、管理対象の安全なアプリケーション キャッシュを使用できます。システムの使用可能なストレージが不足している場合、この内部キャッシュはフラッシュされる可能性がある点に注意してください。

注: アプリをアンインストールすると、いずれかのキャッシュの場所に保存されているファイルは消去されます。

HttpsURLConnection 応答キャッシュを使用する

Android 4.0 では HttpsURLConnection に応答キャッシュが追加されました。次のようにリフレクションを使用して、サポートされているデバイスで HTTP 応答のキャッシュを有効にできます。

Kotlin

    private fun enableHttpResponseCache() {
        try {
            val httpCacheSize: Long = 10L * 1024L * 1024L // 10 MiB
            val httpCacheDir = File(cacheDir, "http")
            Class.forName("android.net.http.HttpResponseCache")
                    .getMethod("install", File::class.java, Long::class.javaPrimitiveType)
                    .invoke(null, httpCacheDir, httpCacheSize)
        } catch (httpResponseCacheNotAvailable: Exception) {
            Log.d(TAG, "HTTP response cache is unavailable.")
        }
    }
    

Java

    private void enableHttpResponseCache() {
      try {
        long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
        File httpCacheDir = new File(getCacheDir(), "http");
        Class.forName("android.net.http.HttpResponseCache")
             .getMethod("install", File.class, long.class)
             .invoke(null, httpCacheDir, httpCacheSize);
      } catch (Exception httpResponseCacheNotAvailable) {
        Log.d(TAG, "HTTP response cache is unavailable.");
      }
    }
    

このサンプルコードでは、以前のリリースに影響を与えることなく、Android 4.0 以降のデバイスで応答キャッシュを有効にします。

キャッシュを導入すると、完全にキャッシュされた HTTP リクエストをローカル ストレージから直接処理できるため、ネットワーク接続を開く必要がなくなります。条件に応じて応答をキャッシュすることで、サーバーからのデータ鮮度を確認できるため、ダウンロードに関連する帯域幅コストを削減できます。

キャッシュされていない応答は、今後のリクエストに備えて応答キャッシュに保存されます。