Bagaimana cara menggunakan cache disk di Picasso?


119

Saya menggunakan Picasso untuk menampilkan gambar di aplikasi android saya:

/**
* 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);
}

Saya telah mengaktifkan debugging dan selalu menunjukkan warna merah dan hijau, tetapi tidak pernah menunjukkan warna kuning

Sekarang jika saya memuat gambar yang sama lain kali dan internet tidak tersedia, gambar tersebut tidak dimuat.

Pertanyaan:

  1. Apakah itu tidak memiliki cache disk lokal?
  2. Bagaimana cara mengaktifkan cache disk karena saya akan menggunakan gambar yang sama beberapa kali.
  3. Apakah saya perlu menambahkan beberapa izin disk ke file manifes Android?

Saya mengalami masalah yang sama. Ini tidak akan menyimpan cache!
Jonathan

Teman-teman, Anda harus melihat Fresco lib facebook. Manajemen cache-nya luar biasa.
Michel Fortes

Jawaban:


229

Inilah yang saya lakukan. Bekerja dengan baik.

Pertama tambahkan OkHttp ke file build gradle dari modul aplikasi:

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'

Kemudian buat kelas diperpanjang 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);

    }
}

tambahkan ke file Manifest sebagai berikut:

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

</application>

Sekarang gunakan Picasso seperti biasa. Tidak ada perubahan.

EDIT:

jika Anda hanya ingin menggunakan gambar yang disimpan dalam cache. Panggil perpustakaan seperti ini. Saya perhatikan bahwa jika kita tidak menambahkan networkPolicy, gambar tidak akan muncul dalam permulaan offline sepenuhnya meskipun mereka di-cache . Kode di bawah menyelesaikan masalah.

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

EDIT # 2

Masalah dengan kode di atas adalah jika Anda mengosongkan cache, Picasso akan terus mencarinya secara offline di cache dan gagal, contoh kode berikut melihat cache lokal, jika tidak ditemukan offline, akan online dan mengisi cache.

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

@Tokopedia , Saya menjawab pertanyaan itu. Dan solusinya berhasil. Tapi ada sedikit klarifikasi yang bisa saya gunakan. Saya memeriksa dokumentasi OkHttp dan mereka tidak menyebutkan unit "cache". Jadi jika ada yang ingin berbagi kebijaksanaan ... ini adalah kesempatan yang bagus.
Sanket Berde

@Tokopedia ya itu masuk akal. Diedit!
Sanket Berde

5
@SanketBerde: Terima kasih atas catatan singkatnya, tetapi saya menemukan bahwa gambar tersebut muncul dari memori hanya jika Aplikasi berjalan di latar belakang (saat offline). jika saya menutup aplikasi, yaitu menghapus aplikasi yang sedang berjalan kemudian membuka aplikasi saya lagi, gambar tidak dimuat dari Cache. Saya telah mengatur kesalahan pemuatan gambar default yang akan datang. Apa yang salah di sini?
TheDevMan

1
Mungkin Picasso telah mengubah cara kerjanya, karena bagi saya, ini berfungsi dengan baik tanpa okhttp dan kebijakan jaringan. Pada permulaan baru, itu langsung mengambil gambar dari disk, dan ketika jaringan offline, itu masih menunjukkannya dengan baik.
zeeshan

1
Dengan okhttp3.OkHttpClientperpustakaan Anda harus menggunakan OkHttp3Downloaderformulir kelas compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
Chuck

46

1) jawaban dari pertanyaan pertama: menurut metode Picasso Doc for With ()

Instance Picasso default global yang dikembalikan dari with () secara otomatis diinisialisasi dengan default yang sesuai untuk sebagian besar implementasi.

  • Cache memori LRU sebesar 15% dari RAM aplikasi yang tersedia
  • Cache disk dari 2% ruang penyimpanan hingga 50MB tetapi tidak kurang dari 5MB.

Tetapi Disk Cache operasi untuk Picasso Default global hanya tersedia di API 14+

2) jawaban dari pertanyaan kedua: Picassogunakan HTTPpermintaan klien untuk Disk Cacheoperasi Jadi Anda dapat membuat milik Anda sendiri http request headermemiliki properti Cache-Controldengan max-age Dan membuat Instance Picasso Statis Anda sendiri daripada Picasso default Dengan menggunakan

1] HttpResponseCache (Catatan: Hanya berfungsi untuk API 13+)
2] OkHttpClient (Bekerja untuk semua API)

Contoh penggunaan OkHttpClientuntuk membuat kelas Picasso Statis Anda sendiri:

  • Pertama buat kelas baru untuk mendapatkan picassoobjek tunggal Anda sendiri

    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;
        }
    
    } 
  • gunakan picassoobjek tunggal Anda sendiri, bukanPicasso.With()

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

3) jawaban untuk pertanyaan ketiga: Anda tidak memerlukan izin disk untuk operasi Cache disk

Referensi : Masalah Github tentang cache disk , dua Pertanyaan telah dijawab oleh @ jake-wharton -> Pertanyaan1 dan Pertanyaan2


4
Tidak, ini tidak berfungsi jika aplikasi ditutup. Setelah aplikasi dihentikan paksa semua gambar menghilang.
nbumakov

2
ini memberi saya kesalahan ini:FATAL EXCEPTION: main java.lang.NoClassDefFoundError: com.squareup.okhttp.OkHttpClient
CIRCLE

@CIRCLE maaf atas keterlambatan, Untuk menggunakan Contoh, Anda perlu untuk men-download pertama [okhttp] ( square.github.io/okhttp ) paket dan [Okio] ( github.com/square/okio ) paket yang digunakan olehokhttp
ahmed hamdy

@CIRCLE mungkin Anda perlu mengunduh paket [okhttp-urlconnection] ( mvnrepository.com/artifact/com.squareup.okhttp/… ) juga
ahmed hamdy

Ini tidak berhasil untuk saya. Gambar sedang dimuat ulang setiap kali saya menggulir ke posisinya di viewPager
Charu

21

Untuk caching, saya akan menggunakan interseptor OkHttp untuk mendapatkan kendali atas kebijakan caching. Lihat contoh ini yang disertakan dalam pustaka OkHttp.

RewriteResponseCacheControl.java

Inilah cara saya menggunakannya dengan Picasso -

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

1
Tidak berfungsi lagi networkInterceptors () mengembalikan daftar yang tidak dapat diubah.
noev

1
@noev di OkHttp 3.x Anda dapat menggunakan pola pembangun (lihat github.com/square/okhttp/wiki/Interceptors ) untuk menambahkan interseptor.
Gaurav B

10

Untuk versi terbaru 2.71828 Ini adalah jawaban Anda.

T1 : Apakah itu tidak memiliki cache disk lokal?

A1 : Ada cache default dalam Picasso dan aliran permintaan seperti ini

App -> Memory -> Disk -> Server

Di mana pun mereka bertemu gambar pertama kali, mereka akan menggunakan gambar itu dan kemudian menghentikan aliran permintaan. Bagaimana dengan aliran respons? Jangan khawatir, ini dia.

Server -> Disk -> Memory -> App

Secara default, mereka akan menyimpan ke disk lokal terlebih dahulu untuk cache penyimpanan yang diperpanjang. Kemudian memori, untuk contoh penggunaan cache.

Anda dapat menggunakan indikator built-in di Picasso untuk melihat di mana gambar terbentuk dengan mengaktifkannya.

Picasso.get().setIndicatorEnabled(true);

Ini akan menunjukkan bendera di sudut kiri atas gambar Anda.

  • Bendera merah berarti gambar tersebut berasal dari server. (Tidak ada caching pada pemuatan pertama)
  • Bendera biru berarti foto-foto tersebut berasal dari disk lokal. (Caching)
  • Bendera hijau berarti gambar tersebut berasal dari memori. (Cache Instance)

T2 : Bagaimana cara mengaktifkan cache disk karena saya akan menggunakan gambar yang sama beberapa kali?

A2 : Anda tidak harus mengaktifkannya. Ini defaultnya.

Yang perlu Anda lakukan adalah NONAKTIFKAN jika Anda ingin gambar Anda selalu segar. Ada 2 cara untuk menonaktifkan caching.

  1. Setel .memoryPolicy()ke NO_CACHE dan / atau NO_STORE dan alurnya akan terlihat seperti ini.

NO_CACHE akan melewatkan mencari gambar dari memori.

App -> Disk -> Server

NO_STORE akan melewatkan menyimpan gambar dalam memori saat memuat gambar pertama.

Server -> Disk -> App
  1. Setel .networkPolicy()ke NO_CACHE dan / atau NO_STORE dan alurnya akan terlihat seperti ini.

NO_CACHE akan melewatkan mencari gambar dari disk.

App -> Memory -> Server

NO_STORE akan melewatkan gambar penyimpanan di disk saat memuat gambar pertama.

Server -> Memory -> App

Anda tidak dapat MENONAKTIFKAN keduanya karena tidak ada gambar yang disimpan dalam cache. Berikut ini contohnya.

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

Aliran tanpa cache dan penyimpanan sepenuhnya akan terlihat seperti ini.

App -> Server //Request

Server -> App //Response

Jadi, Anda mungkin memerlukan ini untuk meminimalkan penggunaan penyimpanan aplikasi Anda juga.

T3 : Apakah saya perlu menambahkan beberapa izin disk ke file manifes android?

A3 : Tidak, tapi jangan lupa untuk menambahkan izin INTERNET untuk permintaan HTTP Anda.


6

1) Picasso secara default memiliki cache (lihat jawaban hamdy ahmed)

2) Jika Anda benar-benar harus mengambil gambar dari cache disk dan kemudian jaringan, saya sarankan untuk menulis pengunduh Anda sendiri:

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

    }
}

Dan di Application singleton dalam metode OnCreate menggunakannya dengan 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) Tidak diperlukan izin untuk menghapus folder cache aplikasi


1

Tambahkan kode followning Application.onCreatelalu gunakan secara normal

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

Jika Anda menyimpan gambar terlebih dahulu, lakukan sesuatu seperti ini di 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);
        }

dan memuat gambar Anda seperti biasa atau dengan cache disk

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

catatan:

Warna merah menunjukkan bahwa gambar diambil dari jaringan .

Warna hijau menunjukkan bahwa gambar diambil dari memori cache .

Warna biru menunjukkan bahwa gambar diambil dari memori disk .

Sebelum merilis aplikasi, hapus atau setel false picasso.setLoggingEnabled(true);, picasso.setIndicatorsEnabled(true);jika tidak diperlukan. Terima kasih


1

Saya tidak tahu seberapa bagus solusi itu tetapi yang pasti yang MUDAH saya gunakan di aplikasi saya dan berfungsi dengan baik

Anda memuat gambar seperti itu

public void loadImage (){
Picasso picasso = Picasso.with(this); 
picasso.setDebugging(true);
picasso.load(quiz.getImageUrl()).into(quizImage);
}

Anda bisa mendapatkan yang bimapseperti itu

Bitmap bitmap = Piccaso.with(this).load(quiz.getImageUrl()).get();

Sekarang sembunyikan itu Bitmapmenjadi JPGfile dan simpan di dalam cache, di bawah ini adalah kode lengkap untuk mendapatkan bimap dan menyimpannya di cache

 Thread thread = new Thread() {
                            public void run() {
                                File file = new File(getActivity().getExternalCacheDir().getAbsolutePath() + "/" +member.getMemberId() + ".jpg");

                                try {
                                    Bitmap bitmap = Picasso.with(getActivity())
                                            .load(uri).get();
                                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100,new FileOutputStream(file));

                                } catch (Exception e) {
                                   e.printStackTrace();
                                }
                            }
                        };
                        thread.start();
                    })

yang get()metode Piccassountuk beberapa alasan yang diperlukan untuk disebut di thread terpisah, saya menyimpan gambar yang juga pada thread yang sama.

Setelah gambar disimpan, Anda bisa mendapatkan semua file seperti itu

List<File> files = new LinkedList<>(Arrays.asList(context.getExternalCacheDir().listFiles()));

Sekarang Anda dapat menemukan file yang Anda cari seperti di bawah ini

for(File file : files){
                if(file.getName().equals("fileyouarelookingfor" + ".jpg")){ // you need the name of the file, for example you are storing user image and the his image name is same as his id , you can call getId() on user to get the file name
                    Picasso.with(getActivity()) // if file found then load it
                            .load(file)
                            .into(mThumbnailImage);
                    return; // return 
                }
        // fetch it over the internet here because the file is not found
       }

0

Saya menggunakan kode ini dan berhasil, mungkin berguna untuk Anda:

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...");
                                }

                            });
                }
            });

}

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.