पिकासो में मैं डिस्क कैशिंग का उपयोग कैसे करूं?


119

मैं अपने एंड्रॉइड ऐप में छवि प्रदर्शित करने के लिए पिकासो का उपयोग कर रहा हूं:

/**
* 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. क्या मुझे एंड्रॉइड मैनिफ़ेस्ट फ़ाइल में कुछ डिस्क अनुमति जोड़ने की आवश्यकता है?

मैं एक ही मुद्दा रहा हूँ। यह कैश नहीं होगा!
जोनाथन

दोस्तों, आपको facebook´ Fresco lib पर एक नज़र डालनी चाहिए। इसका कैश मैनेजमेंट कमाल का है।
मिशेल फोर्ट्स

जवाबों:


229

यह जो मैंने किया है। अच्छा काम करता है।

सबसे पहले ऐप मॉड्यूल के ग्रेड बिल्ड फ़ाइल में OkHttp जोड़ें:

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

EDIT # 2

उपरोक्त कोड के साथ समस्या यह है कि यदि आप कैश को साफ़ करते हैं, तो पिकासो कैश में ऑफ़लाइन खोजता रहेगा और असफल हो जाएगा, निम्न कोड उदाहरण स्थानीय कैश को देखता है, यदि ऑफ़लाइन नहीं पाया जाता है, तो यह ऑनलाइन हो जाता है और कैश को फिर से भरता है।

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

@ArtjomB। , मैंने सवाल का जवाब दिया। और समाधान काम करता है। लेकिन इस छोटे से स्पष्टीकरण मैं उपयोग कर सकते हैं। मैं OkHttp प्रलेखन के माध्यम से चला गया और उन्होंने "कैश" की इकाई का उल्लेख नहीं किया। इसलिए अगर किसी को कुछ ज्ञान साझा करना है ... यह एक अच्छा अवसर है।
संकट बर्डे

@ArtjomB। हाँ जो समझ में आता है। संपादित किया गया!
संकट बर्डे

5
@SanketBerde: त्वरित नोट के लिए धन्यवाद, लेकिन मुझे लगा कि छवि केवल मेमोरी से आ रही है अगर ऐप पृष्ठभूमि में चल रहा है (जब ऑफ़लाइन पर)। अगर मैं ऐप को बंद कर देता हूं, जो चल रहे ऐप्स को साफ़ कर देता है, तो मेरे ऐप को फिर से खोलें, चित्र कैश से लोड नहीं होते हैं। मैंने त्रुटि डिफ़ॉल्ट लोडिंग छवि सेट की है जो आ रही है। यहां क्या गलत हो सकता है?
TheDevMan

1
हो सकता है कि पिकासो बदल गया हो कि चीजें कैसे काम करती हैं, क्योंकि मेरे लिए, यह ओकेटीपी और नेटवर्क पॉलिसी के बिना ठीक काम करता है। एक नई शुरुआत में, यह तुरंत डिस्क से चित्र प्राप्त करता है, और जब नेटवर्क ऑफ़लाइन होता है, तब भी यह उन्हें ठीक दिखाता है।
जीशान

1
okhttp3.OkHttpClientलाइब्रेरी के साथ आपको OkHttp3Downloaderक्लास फॉर्मcompile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
चक

46

1) पहले प्रश्न का उत्तर: पिकासो डॉक्टर के साथ () विधि के अनुसार

वैश्विक डिफ़ॉल्ट पिकासो उदाहरण के साथ वापस लौटा () स्वचालित रूप से उन डिफ़ॉल्ट के साथ आरंभ किया गया है जो अधिकांश कार्यान्वयन के लिए उपयुक्त हैं।

  • LRU मेमोरी कैश 15% उपलब्ध एप्लिकेशन रैम
  • 50% तक 2% स्टोरेज स्पेस का डिस्क कैश लेकिन 5MB से कम नहीं।

लेकिन Disk Cache वैश्विक डिफ़ॉल्ट पिकासो के लिए ऑपरेशन केवल एपीआई 14+ पर उपलब्ध है

2) दूसरा सवाल का जवाब: Picassoका उपयोग HTTPकरने के लिए ग्राहक के अनुरोध के Disk Cacheआपरेशन तो आप अपने खुद के लिए कर सकते हैं http request headerसंपत्ति है Cache-Controlके साथ max-age और का उपयोग करके पिकासो डिफ़ॉल्ट के बजाय अपने खुद के स्टेटिक पिकासो उदाहरण बनाने

1] HttpResponseCache (नोट: केवल API 13+ के लिए काम करता है)
2] OkHttpClient (सभी एपीआई के लिए काम करता है)

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इसके बजाय अपनी खुद की सिंगलटन ऑब्जेक्ट का उपयोग करेंPicasso.With()

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

3) तीसरे प्रश्न का उत्तर: आपको डिस्क कैश ऑपरेशन के लिए किसी भी डिस्क अनुमति की आवश्यकता नहीं है

संदर्भ : डिस्क कैश के बारे में गितुब मुद्दा , दो प्रश्नों का उत्तर @ जेक-व्हार्टन द्वारा दिया गया है -> प्रश्न 1 और प्रश्न 2


4
नहीं, यदि ऐप बंद था तो यह काम नहीं करेगा। एप्लिकेशन को बल देने के बाद सभी चित्र गायब हो गए।
nbumakov

2
यह मुझे यह त्रुटि दे रहा है:FATAL EXCEPTION: main java.lang.NoClassDefFoundError: com.squareup.okhttp.OkHttpClient
CIRCLE

@CIRCLE देर से आने के लिए क्षमा करें, उदाहरण के लिए, आपको पहले [okhttp] ( square.github.io/okhttp ) पैकेज और [okio] ( github.com/square/okio ) पैकेज डाउनलोड करने की आवश्यकता है जिसका उपयोग किया गया हैokhttp
अहमद

@CIRCLE हो सकता है आप डाउनलोड [okhttp-urlconnection] (करने की जरूरत है mvnrepository.com/artifact/com.squareup.okhttp/... ) पैकेज भी
अहमद hamdy

यह मेरे लिए काम नहीं कर रहा है। प्रत्येक बार जब मैं दृश्य में उनकी स्थिति को स्क्रॉल करता हूं तो छवियाँ पुनः लोड हो रही हैं
चारु

21

कैशिंग के लिए, मैं कैशिंग पॉलिसी पर नियंत्रण पाने के लिए OkHttp इंटरसेप्टर्स का उपयोग करूंगा । इस नमूने को देखें जो 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);

1
अब काम नहीं करता है networkInterceptors () एक अपरिवर्तनीय सूची देता है।
नोव

1
Oknttp 3.x में @noev इंटरसेप्टर्स को जोड़ने के लिए आप बिल्डर पैटर्न ( github.com/square/okhttp/wiki/Interceptors देखें ) का उपयोग कर सकते हैं ।
गौरव बी

10

सबसे अद्यतन संस्करण 2.71828 के लिए ये आपके उत्तर हैं।

Q1 : क्या इसमें स्थानीय डिस्क कैश नहीं है?

A1 : पिकासो के भीतर डिफ़ॉल्ट कैशिंग है और अनुरोध प्रवाह इस तरह से है

App -> Memory -> Disk -> Server

वे जहां भी अपनी छवि से पहले मिले, वे उस छवि का उपयोग करेंगे और फिर अनुरोध प्रवाह रोक देंगे। प्रतिक्रिया प्रवाह के बारे में क्या? चिंता मत करो, यहाँ यह है।

Server -> Disk -> Memory -> App

डिफ़ॉल्ट रूप से, वे विस्तारित कैश रखने के लिए पहले एक स्थानीय डिस्क में संग्रहीत करेंगे। फिर मेमोरी, कैश के उदाहरण के उपयोग के लिए।

आप पिकासो में अंतर्निहित संकेतक का उपयोग करके यह देख सकते हैं कि इसे सक्षम करने से चित्र कहां बनते हैं।

Picasso.get().setIndicatorEnabled(true);

यह आपकी तस्वीरों के ऊपरी बाएँ कोने पर एक झंडा दिखाएगा।

  • लाल झंडे का मतलब है कि चित्र सर्वर से आते हैं। (पहले लोड पर कोई कैशिंग नहीं)
  • ब्लू फ्लैग का मतलब है कि तस्वीरें स्थानीय डिस्क से आती हैं। (कैशिंग)
  • हरे झंडे का मतलब है कि चित्र मेमोरी से आते हैं। (इंस्टेंस कैशिंग)

Q2 : मैं डिस्क कैशिंग कैसे सक्षम कर सकता हूं क्योंकि मैं एक ही छवि का कई बार उपयोग करूंगा?

A2 : आपको इसे सक्षम करने की आवश्यकता नहीं है। यह डिफ़ॉल्ट है।

आपको क्या करने की आवश्यकता होगी है अक्षम है जब आप अपने छवियों को हमेशा ताजा चाहते हैं कि उसे। विकलांग कैशिंग का 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

आप पूरी तरह से कोई कैशिंग छवियों के लिए न तो अक्षम कर सकते हैं। यहाँ एक उदाहरण है।

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

तो, आपको अपने एप्लिकेशन संग्रहण उपयोग को भी छोटा करने की आवश्यकता हो सकती है।

Q3 : क्या मुझे एंड्रॉइड मैनिफ़ेस्ट फ़ाइल में कुछ डिस्क अनुमति जोड़ने की आवश्यकता है?

A3 : नहीं, लेकिन अपने HTTP अनुरोध के लिए INTERNET अनुमति जोड़ना न भूलें।


6

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

    }
}

और अनुप्रयोग सिंगलटन मेथड ऑनक्रीट में इसे पिकासो के साथ प्रयोग करें:

        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) डिफाल्ट एप्लीकेशन कैश फोल्डर के लिए किसी अनुमति की आवश्यकता नहीं है


1

Application.onCreateउसके बाद followning कोड जोड़ें और इसे सामान्य उपयोग करें

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

ध्यान दें:

लाल रंग इंगित करता है कि छवि नेटवर्क से ली गई है

हरा रंग इंगित करता है कि छवि कैश मेमोरी से ली गई है

नीला रंग इंगित करता है कि छवि डिस्क मेमोरी से ली गई है

एप्लिकेशन को जारी करने से पहले हटा दें या सेट करें false picasso.setLoggingEnabled(true);, picasso.setIndicatorsEnabled(true);यदि आवश्यक नहीं है। thankx


1

मुझे नहीं पता कि वह समाधान कितना अच्छा है, लेकिन यह निश्चित रूप से आसान है जिसे मैंने अभी अपने ऐप में उपयोग किया है और यह ठीक काम कर रहा है

आप उस तरह की छवि लोड करते हैं

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

आप bimapजैसा चाहें वैसा पा सकते हैं

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

अब भी बयान है कि Bitmapएक में JPGफ़ाइल और कैश में में दुकान, नीचे bimap हो रही है और यह कैशिंग के लिए पूरा कोड है

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

अलग-अलग थ्रेड पर कॉल करने के लिए आवश्यक किसी कारण की get()विधि Piccasso, मैं उस छवि को उसी थ्रेड पर भी सहेज रहा हूं।

एक बार इमेज सेव हो जाने के बाद आप उस तरह की सभी फाइल प्राप्त कर सकते हैं

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

अब आप उस फ़ाइल को पा सकते हैं जिसे आप नीचे देख रहे हैं

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

मैं इस कोड का उपयोग करता हूं और काम करता हूं, शायद आपके लिए उपयोगी हो:

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

                            });
                }
            });

}

-3

मेरे पास एक ही समस्या थी और इसके बजाय ग्लाइड लाइब्रेरी का इस्तेमाल किया। कैश वहां के बॉक्स से बाहर है। https://github.com/bumptech/glide


ग्लाइड पिकासो की तुलना में 5 गुना अधिक कोड है। जब पहले से ही okhttp का उपयोग कर रहे हैं, तो पिकासो का उपयोग करना बेहतर है
अलेक्जेंडर फार्बर

2
दोनों पुस्तकालयों अलग ढंग से कैशिंग लेकिन कैश का उपयोग करें: medium.com/@multidots/glide-vs-picasso-930eed42b81d
Orri
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.