web-dev-qa-db-ja.com

Picassoでディスクキャッシュを使用するにはどうすればよいですか?

Picassoを使用してAndroidアプリに画像を表示しています:

/**
* load image.This is within a activity so this context is activity
*/
public void loadImage (){
    Picasso picasso = Picasso.with(this); 
    picasso.setDebugging(true);
    picasso.load(quiz.getImageUrl()).into(quizImage);
}

デバッグを有効にすると、常に赤と緑のいずれかが表示されますが、黄色は表示されません

次回同じ画像をロードし、インターネットが利用できない場合、画像はロードされません。

質問:

  1. ローカルディスクキャッシュがありませんか?
  2. 同じイメージを複数回使用するため、ディスクキャッシュを有効にするにはどうすればよいですか。
  3. Androidマニフェストファイルにディスクアクセス許可を追加する必要がありますか?
111
user93796

これは私がやったことです。うまくいく。

まず、OkHttpをappモジュールのgradleビルドファイルに追加します。

compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.10.0'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'

次に、Applicationを拡張するクラスを作成します

import Android.app.Application;

import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;

public class Global extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        Picasso.Builder builder = new Picasso.Builder(this);
        builder.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE));
        Picasso built = builder.build();
        built.setIndicatorsEnabled(true);
        built.setLoggingEnabled(true);
        Picasso.setSingletonInstance(built);

    }
}

次のようにマニフェストファイルに追加します。

<application
        Android:name=".Global"
        .. >

</application>

通常どおりにピカソを使用します。変更なし。

編集:

キャッシュされた画像のみを使用する場合。このようにライブラリを呼び出します。 networkPolicyを追加しない場合、イメージは表示されません完全にオフラインで起動キャッシュされていてもであることに気付きました。以下のコードは問題を解決します。

Picasso.with(this)
            .load(url)
            .networkPolicy(NetworkPolicy.OFFLINE)
            .into(imageView);

編集#2

上記のコードの問題は、キャッシュをクリアすると、Picassoがキャッシュでオフラインで検索を続けて失敗することです。次のコード例では、ローカルキャッシュを調べ、オフラインで見つからない場合はオンラインになり、キャッシュを補充します。

Picasso.with(getActivity())
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView, new Callback() {
    @Override
    public void onSuccess() {

    }

    @Override
    public void onError() {
        //Try again online if cache failed
        Picasso.with(getActivity())
                .load(posts.get(position).getImageUrl())
                .error(R.drawable.header)
                .into(imageView, new Callback() {
            @Override
            public void onSuccess() {

            }

            @Override
            public void onError() {
                Log.v("Picasso","Could not fetch image");
            }
        });
    }
});
222
Sanket Berde

1)最初の質問の答え: With with()メソッドのPicasso Doc

With()から返されるグローバルなデフォルトPicassoインスタンスは、ほとんどの実装に適したデフォルトで自動的に初期化されます。

  • 使用可能なアプリケーションRAMの15%のLRUメモリキャッシュ
  • 最大50MBのストレージ領域が2%で、5MB以上のディスクキャッシュ。

しかし、グローバルなデフォルトのピカソのDisk Cache操作は、API 14+でのみ利用可能です

2)2番目の質問の答え:PicassoHTTPクライアント要求をDisk Cache操作に使用しますSo独自のhttp request headerCache-Controlを持つプロパティmax-ageを作成し、デフォルトのピカソの代わりに独自の静的ピカソインスタンスを作成できます

1] HttpResponseCache (注:API 13+でのみ機能します)
2] OkHttpClient (すべてのAPIで動作)

OkHttpClientを使用して独自の静的ピカソクラスを作成する例

  • 最初に新しいクラスを作成して、独自のシングルトンpicassoオブジェクトを取得します

    import Android.content.Context;
    import com.squareup.picasso.Downloader;
    import com.squareup.picasso.OkHttpDownloader;
    import com.squareup.picasso.Picasso;
    
    public class PicassoCache {
    
        /**
         * Static Picasso Instance
         */
        private static Picasso picassoInstance = null;
    
        /**
         * PicassoCache Constructor
         *
         * @param context application Context
         */
        private PicassoCache (Context context) {
    
            Downloader downloader   = new OkHttpDownloader(context, Integer.MAX_VALUE);
            Picasso.Builder builder = new Picasso.Builder(context);
                builder.downloader(downloader);
    
            picassoInstance = builder.build();
        }
    
        /**
         * Get Singleton Picasso Instance
         *
         * @param context application Context
         * @return Picasso instance
         */
        public static Picasso getPicassoInstance (Context context) {
    
            if (picassoInstance == null) {
    
                new PicassoCache(context);
                return picassoInstance;
            }
    
            return picassoInstance;
        }
    
    } 
    
  • Picasso.With()の代わりに独自のシングルトンpicassoオブジェクトを使用する

PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)

3)3番目の質問に対する答え:ディスクキャッシュ操作にディスクアクセス許可は必要ありません

参考文献ディスクキャッシュに関するGithubの問題 、2つの質問に答えました @ jake-wharton -> Question1 および Question2

45
ahmed hamdy

キャッシングの場合、OkHttpinterceptorsを使用して、キャッシングポリシーを制御します。 OkHttpライブラリに含まれているこのサンプルをご覧ください。

RewriteResponseCacheControl.Java

これをピカソで使用する方法です-

OkHttpClient okHttpClient = new OkHttpClient();
    okHttpClient.networkInterceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response originalResponse = chain.proceed(chain.request());
            return originalResponse.newBuilder().header("Cache-Control", "max-age=" + (60 * 60 * 24 * 365)).build();
        }
    });

    okHttpClient.setCache(new Cache(mainActivity.getCacheDir(), Integer.MAX_VALUE));
    OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
    Picasso picasso = new Picasso.Builder(mainActivity).downloader(okHttpDownloader).build();
    picasso.load(imageURL).into(viewHolder.image);
21
Gaurav B

1)デフォルトではピカソにキャッシュがあります(アーメドハンディの回答を参照)

2)本当にディスクキャッシュとネットワークから画像を取得する必要がある場合は、独自のダウンローダーを作成することをお勧めします。

public class OkHttpDownloaderDiskCacheFirst extends OkHttpDownloader {
    public OkHttpDownloaderDiskCacheFirst(OkHttpClient client) {
        super(client);
    }

    @Override
    public Response load(Uri uri, int networkPolicy) throws IOException {
        Response responseDiskCache = null;
        try {
            responseDiskCache = super.load(uri, 1 << 2); //NetworkPolicy.OFFLINE
        } catch (Exception ignored){} // ignore, handle null later

        if (responseDiskCache == null || responseDiskCache.getContentLength()<=0){
            return  super.load(uri, networkPolicy); //user normal policy
        } else {
            return responseDiskCache;
        }

    }
}

そして、メソッドOnCreateのアプリケーションシングルトンでは、picassoで使用します。

        OkHttpClient okHttpClient = new OkHttpClient();

        okHttpClient.setCache(new Cache(getCacheDir(), 100 * 1024 * 1024)); //100 MB cache, use Integer.MAX_VALUE if it is too low
        OkHttpDownloader downloader = new OkHttpDownloaderDiskCacheFirst(okHttpClient); 

        Picasso.Builder builder = new Picasso.Builder(this);

        builder.downloader(downloader);

        Picasso built = builder.build();

        Picasso.setSingletonInstance(built);

3)デフォルトのアプリケーションキャッシュフォルダーにアクセス許可は必要ありません

6
tsm

最新のバージョン2.71828の場合これらはあなたの答えです。

Q1:ローカルディスクキャッシュがありませんか?

A1:Picassoにはデフォルトのキャッシュがあり、リクエストフローは次のようになります

App -> Memory -> Disk -> Server

最初に画像に出会ったところはどこでも、その画像を使用してからリクエストフローを停止します。応答フローはどうですか?心配しないでください、ここにあります。

Server -> Disk -> Memory -> App

デフォルトでは、拡張保持キャッシュのために最初にローカルディスクに保存されます。次に、メモリ、キャッシュのインスタンス使用量。

これを有効にすると、Picassoの組み込みインジケーターを使用して、画像が形成される場所を確認できます。

Picasso.get().setIndicatorEnabled(true);

写真の左上に旗が表示されます。

  • フラグは、イメージがサーバーからのものであることを意味します。 (初回ロード時にキャッシュなし)
  • フラグは、写真がローカルディスクからのものであることを意味します。 (キャッシュ)
  • フラグは、画像がメモリから取得されることを意味します。 (インスタンスキャッシング)

Q2:同じイメージを複数回使用するため、ディスクキャッシュを有効にするにはどうすればよいですか?

A2:有効にする必要はありません。これがデフォルトです。

あなたがする必要があるのは、画像を常に新鮮にしたいときにDISABLEです。 2方向の無効化されたキャッシュがあります。

  1. .memoryPolicy()NO_CACHEおよび/またはNO_STOREおよびフローは次のようになります。

NO_CACHEは、メモリからの画像の検索をスキップします。

App -> Disk -> Server

NO_STOREは、最初にイメージをロードするときにメモリ内のイメージの保存をスキップします。

Server -> Disk -> App
  1. .networkPolicy()NO_CACHEおよび/またはNO_STOREおよびフローは次のようになります。

NO_CACHEは、ディスクからの画像の検索をスキップします。

App -> Memory -> Server

NO_STOREは、最初のイメージのロード時にディスク内のイメージの保存をスキップします。

Server -> Memory -> App

DISABLEどちらでもない場合、キャッシュイメージは完全にありません。以下に例を示します。

Picasso.get().load(imageUrl)
             .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
             .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
             .fit().into(banner);

キャッシュも保存もまったくないフローは、このようになります。

App -> Server //Request

Server -> App //Response

そのため、アプリのストレージ使用量を最小化するためにこれが必要になる場合があります。

Q:Androidマニフェストファイルにディスクアクセス許可を追加する必要がありますか?

A:いいえ。ただし、HTTPリクエストにインターネットアクセス許可を追加することを忘れないでください。

1

私はこのコードを使用して作業しました。

public static void makeImageRequest(final View parentView,final int id, final String imageUrl) {

    final int defaultImageResId = R.mipmap.user;
    final ImageView imageView = (ImageView) parentView.findViewById(id);
    Picasso.with(context)
            .load(imageUrl)
            .networkPolicy(NetworkPolicy.OFFLINE)
            .into(imageView, new Callback() {
                @Override
                public void onSuccess() {
                Log.v("Picasso","fetch image success in first time.");
                }

                @Override
                public void onError() {
                    //Try again online if cache failed
                    Log.v("Picasso","Could not fetch image in first time...");
                    Picasso.with(context).load(imageUrl).networkPolicy(NetworkPolicy.NO_CACHE)
                            .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).error(defaultImageResId)
                            .into(imageView, new Callback() {

                                @Override
                                public void onSuccess() {
                                    Log.v("Picasso","fetch image success in try again.");
                                }

                                @Override
                                public void onError() {
                                  Log.v("Picasso","Could not fetch image again...");
                                }

                            });
                }
            });

}
0
Iman Marashi

Application.onCreateに次のコードを追加して、通常どおり使用します

    Picasso picasso = new Picasso.Builder(context)
            .downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
            .build();
    picasso.setIndicatorsEnabled(true);
    picasso.setLoggingEnabled(true);
    Picasso.setSingletonInstance(picasso);

最初に画像をキャッシュする場合は、ProductImageDownloader.doBackgroundでこのようなことをしてください

final Callback callback = new Callback() {
            @Override
            public void onSuccess() {
                downLatch.countDown();
                updateProgress();
            }

            @Override
            public void onError() {
                errorCount++;
                downLatch.countDown();
                updateProgress();
            }
        };
        Picasso.with(context).load(Constants.imagesUrl+productModel.getGalleryImage())
                .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
        Picasso.with(context).load(Constants.imagesUrl+productModel.getLeftImage())
                .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
        Picasso.with(context).load(Constants.imagesUrl+productModel.getRightImage())
                .memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);

        try {
            downLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(errorCount == 0){
            products.remove(productModel);
            productModel.isDownloaded = true;
            productsDatasource.updateElseInsert(productModel);
        }else {
            //error occurred while downloading images for this product
            //ignore error for now
            // FIXME: 9/27/2017 handle error
            products.remove(productModel);

        }
        errorCount = 0;
        downLatch = new CountDownLatch(3);

        if(!products.isEmpty() /*&& testCount++ < 30*/){
            startDownloading(products.get(0));
        }else {
            //all products with images are downloaded
            publishProgress(100);
        }

通常のように、またはディスクキャッシュを使用して画像を読み込みます

    Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
        .networkPolicy(NetworkPolicy.OFFLINE)
        .placeholder(R.drawable.GalleryDefaultImage)
        .error(R.drawable.GalleryDefaultImage)
        .into(viewGallery);

注意:

色は、画像がネットワークから取得されることを示します。

色は、画像がキャッシュメモリから取得されることを示します。

色は、イメージがディスクメモリから取得されることを示します。

アプリをリリースする前に、falsepicasso.setLoggingEnabled(true);を削除または設定し、必要でない場合はpicasso.setIndicatorsEnabled(true);を設定します。ありがとう

0
Qamar