लक्ष्य वस्तु का onBitmapLaded पहले लोड पर नहीं बुलाया गया


126

मेरे समारोह में:

public void getPointMarkerFromUrl(final String url, final OnBitmapDescriptorRetrievedListener listener) {
final int maxSize = context.getResources().getDimensionPixelSize(R.dimen.icon_max_size);
Target t = new Target() {
  @Override
  public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
    if (bitmap != null)
      listener.bitmapRetrieved(getBitmapDescriptorInCache(url, bitmap));
    else
      loadDefaultMarker(listener);
  }

  @Override
  public void onBitmapFailed(Drawable errorDrawable) {
    loadDefaultMarker(listener);
  }

  @Override
  public void onPrepareLoad(Drawable placeHolderDrawable) {
  }
};

Picasso.with(context)
    .load(url)
    .resize(maxSize, maxSize)
    .into(t);
}

OnBitmapLoaded () को पहली बार मेरे द्वारा चित्रों को लोड करने को पहली बार नहीं कहा जाता है। मैंने कुछ विषय पढ़े हैं जैसे https://github.com/square/picasso/issues/39 जो भ्रूण (लक्ष्य टी) विधि का उपयोग करने की सलाह देता है (यह कमजोर संदर्भ की समस्या लगती है ...), लेकिन यह फ़ंक्शन picasso (2.3.2) की अंतिम रिलीज़ में उपलब्ध नहीं है। मेरे पास केवल एक भ्रूण () विधि है, लेकिन मैं एक ही समय में (mytarget) उपयोग नहीं कर सकता

क्या आप मुझे बता सकते हैं कि कस्टम लक्ष्य कृपया के साथ भ्रूण () का उपयोग कैसे करें? धन्यवाद।

दस्तावेज़: http://square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--


1
okhttp 2.0.0 का उपयोग करना सुनिश्चित करें, मैं उसी मुद्दे का सामना करता हूं जब पिकासो 2.3.2 का उपयोग Okhttp 1.6.0
hakim

github.com/square/okhttp afaik, okhttp (और okio) लाइब्रेरी को शामिल करने के लिए यदि आप पिकासो 2.3.2 का उपयोग कर रहे हैं तो यह अनिवार्य है। क्या आप ग्रहण या एंड्रॉइड स्टूडियो का उपयोग कर रहे हैं?
हकीम

मैं IntelliJ का उपयोग कर रहा हूं। मैंने अपनी ढाल निर्भरता देखी है, मैंने ओकटेट नहीं देखा ... पिकासो इसके बिना काम करने लगता है
psv

@psv आपने मार्करों के साथ नीचे समाधान कैसे लागू किया?
मुस्तफा गुवेन

जवाबों:


247

जैसा कि अन्य उत्तरदाताओं (@lukas और @mradzinski) ने उल्लेख किया है, पिकासो केवल Targetऑब्जेक्ट के लिए एक कमजोर संदर्भ रखता है । जब आप अपनी किसी Targetएक कक्षा में एक मजबूत संदर्भ संग्रहीत कर सकते हैं, तो यह अभी भी समस्याग्रस्त हो सकता है यदि Targetसंदर्भ Viewकिसी भी तरीके से हो, क्योंकि आप प्रभावी Viewरूप से उस पर भी एक मजबूत संदर्भ रख रहे होंगे (जो कि पिकासो की एक बात है। स्पष्ट रूप से आप से बचने में मदद करता है)।

यदि आप इस स्थिति में हैं, तो मैं निम्नलिखित Targetको टैग करने की सलाह दूंगा View:

final ImageView imageView = ... // The view Picasso is loading an image into
final Target target = new Target{...};
imageView.setTag(target);

इस दृष्टिकोण का पिकासो को आपके लिए सब कुछ संभालने देने का लाभ है। यह WeakReferenceआपके प्रत्येक दृश्य के लिए वस्तुओं का प्रबंधन करेगा - जैसे ही किसी की जरूरत नहीं है, जो भी Targetप्रसंस्करण छवि को भी जारी किया जाएगा, इसलिए आप लंबे समय तक रहने वाले लक्ष्यों के कारण मेमोरी लीक के साथ फंस नहीं रहे हैं, लेकिन आपका लक्ष्य अंतिम होगा जब तक इसका दृश्य जीवित है।


15
मेरा दिन बचाया। धन्यवाद।
साइबर

24
मेरे पास एक छवि दृश्य नहीं है, मैं इस समस्या को कैसे हल कर सकता हूं? इस तरह की स्थितियों से निपटने के दौरान, gc आपका सबसे खराब दुश्मन है
tim687

3
आप इसे एक ArrayList <लक्ष्य> में भी स्टोर कर सकते हैं और यह काम करेगा, बस उस सरणीसूची को साफ़ करना याद रखें :-)
ओलिवर डिक्सन

2
OnBitmapLoaded और onBitmapFailed में, मैं बिटमैप को संसाधित करने के बाद imageView.setTag (नल) भी कर रहा हूं। क्या इसकी जरूरत नहीं है?
जगुआर

1
धन्यवाद! बस मेरी जान बचाई :)
yusufiga

55

पिकासो लक्ष्य वस्तु का एक मजबूत संदर्भ नहीं रखता है, इस प्रकार यह कचरा एकत्र किया जा रहा है और onBitmapLoadedइसे नहीं कहा जाता है।

समाधान काफी सरल है, बस इसके लिए एक मजबूत संदर्भ बनाएं Target

public class MyClass {
   private Target mTarget = new Target() {...};

   public void getPointMarkerFromUrl(final String url, final OnBitmapDescriptorRetrievedListener listener) {

         Picasso.with(context)
         .load(url)
         .resize(maxSize, maxSize)
         .into(mTarget);
   }
}      

2
या अपना Viewकार्यान्वयन करें Target
dnkoutso 23

डॉक्स में, यह कहता है कि आपको ओवरराइड Object.equals(Object)और Object.hashCode()तरीके हैं। क्या आपके पास काम करने का नमूना है?
चिप

यह कहाँ लिखा है मुझे अभी भी अपने लक्ष्य () के लिए एक मजबूत संदर्भ देकर मेरी समस्या है।
psv

मैंने अब okHttp स्थापित कर लिया है, यह लोड करने के लिए थोड़ा तेज़ है लेकिन मुझे अभी भी पहले लॉन्च में यही समस्या है। कोई विचार ?
psv

@psv: क्या आपको पिकासो के पहले लॉन्च मुद्दे को हल करने के लिए मिला था? मेरी भी यही समस्या है? यदि आपने हल किया है तो आपने इसे कैसे हल किया?
डेवमैन

25

अगर मेरे पास ImageView था तो मैं इस तरह से सरल बनाऊंगा: imageView.setTag (लक्ष्य);

मैं बिटमैप को सूचनाओं में लोड करने के लिए अगले समाधान का उपयोग करता हूं, इसलिए मुझे केवल बिटमैप की आवश्यकता है।

तो सेट चुड़ैल लक्ष्य वस्तुओं को स्टोर करेगा और उन्हें फिनिशिंग लोड करने पर हटा देगा।

final Set<Target> protectedFromGarbageCollectorTargets = new HashSet<>();

private void loadBitmap(String url) {
   Target bitmapTarget = new BitmapTarget(nEvent);
   protectedFromGarbageCollectorTargets.add(bitmapTarget);
   Picasso.with(context).load(url).into(bitmapTarget);
}

class BitmapTarget implements Target {

        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {

                    //handle bitmap
                    protectedFromGarbageCollectorTargets.remove(this);
                }
            }
        }

        @Override
        public void onBitmapFailed(Drawable drawable) {
            protectedFromGarbageCollectorTargets.remove(this);
        }

        @Override
        public void onPrepareLoad(Drawable drawable) {

        }
    }

13
ImageView profile = new ImageView(context);
        Picasso.with(context).load(URL).into(profile, new Callback() {
            @Override
            public void onSuccess() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {//You will get your bitmap here

                        Bitmap innerBitmap = ((BitmapDrawable) profile.getDrawable()).getBitmap();
                    }
                }, 100);
            }

            @Override
            public void onError() {

            }
        });

1
यह मेरी समस्या का भी हल है। मैं अधिसूचना के साथ इसका इस्तेमाल करना चाहता था। कभी-कभी छवि लक्ष्य के साथ डाउनलोड हो रही थी और कभी-कभी नहीं। लेकिन ImageView का उपयोग करने के बाद मैं हर बार छवियों को लोड करने में सक्षम था
रवीश GS

1
मेरे मामले में, सभी को छोड़कर, यह सबसे अच्छा समाधान था!
नूर हुसैन

4

यहाँ उन लोगों के लिए समाधान है जो एक दृश्य का उपयोग नहीं कर रहे हैं। यह सहायक विधि किसी लक्ष्य को अस्थायी रूप से संग्रहीत करने के लिए एक सूची का उपयोग करती है जब तक कि कोई परिणाम वापस नहीं किया जाता है ताकि यह gc'd न हो:

private List<Target> targets = new ArrayList<>();

public void downloadBitmap(final Context context, final String url, final MyCallback callback) {
    Target target = new Target() {

        @Override
        public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
            targets.clear();
            callback.onSuccess(bitmap);
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
            targets.clear();
            callback.onFailure(null);
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
        }
    };
    targets.add(target);
    Picasso.with(context).load(url).into(target);
}

3

@Lukas ने कहा (और उद्धृत करते हुए), पिकासो लक्ष्य वस्तु का एक मजबूत संदर्भ नहीं रखता है। कचरा संग्रह से बचने के लिए आपको ऑब्जेक्ट का एक मजबूत संदर्भ रखना होगा।

लाने के बारे में () विधि। यह प्रलेखन में बहुत स्पष्ट है कि लाने के लिए एक छवि दृश्य के साथ प्रयोग नहीं किया जा रहा है (न ही कोई लक्ष्य है, यह सिर्फ कैश को "वार्म" करना है और कुछ नहीं है, इसलिए आप इसका उपयोग करने में सक्षम नहीं हैं। चाहते हैं।

मैं आपको सलाह देता हूं कि @lukas जैसे मजबूत संदर्भ को समझाया जाए, यह काम करना चाहिए। यदि कृपया प्रोजेक्ट के GitHub पृष्ठ पर एक नया मुद्दा न खोलें।


3

मुझे इसी तरह की समस्या का सामना करना पड़ा और लक्ष्य के संदर्भ में रखने से मुझे बिल्कुल मदद नहीं मिली, इसलिए मैंने निम्नलिखित कोड का उपयोग किया जो एक बिटमैप देता है:


Bitmap bitmap = picasso.with(appContext).load(url).get();

नीचे की ओर -> कोई कॉलबैक नहीं है और आप इस फ़ंक्शन को मुख्य थ्रेड पर कॉल नहीं कर सकते हैं, आपको इस फ़ंक्शन को पृष्ठभूमि थ्रेड पर निम्न उदाहरण में चलाना होगा:


handlerThread = new HandlerThread(HANDLER_THREAD_NAME);
handlerThread.start();

Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
    @Override
    public void run() {
        Bitmap bitmap = null;
        try {
            bitmap = picasso.with(appContext).load(url).get();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (bitmap != null) {
                //do whatever you wanna do with the picture.
                //for me it was using my own cache
                imageCaching.cacheImage(imageId, bitmap);
            }
        }
    }
});

एक और चीज जो पूरी तरह से बेहतर काम करती है वह है ग्लाइड का उपयोग करना !

मुझे उन दोनों का उपयोग करने की आवश्यकता थी क्योंकि मेरी परियोजना का उद्देश्य एक चित्र गैलरी दिखाने के लिए एपीआई डाउनलोड करने के लिए 2 अलग-अलग छवि का उपयोग करना था और उपयोगकर्ता को यह चुनने की क्षमता प्रदान करना था कि कौन सा एपीआई उपयोग करना है।

मुझे कहना है, मैं परिणामों से चकित था, ग्लाइड की एपी ने हर पहलू में लापरवाही से काम किया (ग्लाइड के लक्ष्य का कमजोर संदर्भ नहीं है) पाइलो ने मुझे नरक दिया (यह मेरा पहली बार ग्लाइड का उपयोग कर रहा था, मैंने आमतौर पर अब तक पिकासो का उपयोग किया था, आज लगता है कि यह परिवर्तन करने वाला है ^ ^)।


0

मैंने उसी मुद्दे का सामना किया था, लेकिन जब मैं नीचे बताए अनुसार निर्भरता को बदलता हूं, तो यह अब ठीक से काम करता है।

 implementation 'com.squareup.picasso:picasso:2.5.2'
 implementation 'com.squareup.okhttp:okhttp:2.3.0'
 implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.