onBitmapLoaded / Hedef nesnenin ilk yüklemede çağrılmaması


126

Benim işlevimde:

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 (), resimleri ilk yüklediğimde hiçbir zaman çağrılmaz. Getirme (Hedef t) yöntemini kullanmayı öneren https://github.com/square/picasso/issues/39 gibi bazı konular okudum (zayıf bir başvuru sorunu gibi görünüyor ...), ancak bu işlev picasso (2.3.2) 'nin son sürümünde mevcut değildir. Yalnızca bir fetch () yöntemim var, ancak aynı anda (mytarget) işlevini kullanamıyorum

Lütfen bana fetch () işlevini özel bir Hedef ile nasıl kullanacağımı açıklar mısınız? Teşekkür ederim.

Doküman: http://square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--


1
okhttp 2.0.0'ı kullandığınızdan emin olun, Picasso 2.3.2'yi Okhttp 1.6.0 ile kullanırken aynı sorunla karşılaşıyorum
hakim

github.com/square/okhttp afaik, okhttp (ve okio) kitaplığını eklemek için Picasso 2.3.2 kullanıyorsanız zorunludur. Eclipse mi yoksa android stüdyo mu kullanıyorsunuz?
hakim

IntelliJ kullanıyorum. Gradle bağımlılıklarımı gördüm, okhttp görmedim ... Picasso onsuz çalışıyor gibi görünüyor
psv

@psv Aşağıdaki çözümü işaretçilerle nasıl uyguladınız?
Mustafa Güven

Yanıtlar:


248

Diğer yanıt verenlerin (@lukas ve @mradzinski) belirttiği gibi, Picasso Targetnesneye yalnızca zayıf bir referans veriyor . TargetSınıflarınızdan birinde güçlü bir referans depolayabilseniz de, Targetreferanslar Viewherhangi bir şekilde a ise, bu yine de sorunlu olabilir , çünkü buna da güçlü bir atıfta bulunacaksınız View(Picasso'nun yaptığı şeylerden biri budur). açıkça kaçınmanıza yardımcı olur).

Bu durumda ise, ben etiketleme öneriyoruz Targetiçin View:

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

Bu yaklaşım, Picasso'nun sizin için her şeyi halletmesine izin verme avantajına sahiptir. WeakReferenceGörünümlerinizin her biri için nesneleri yönetecektir - artık ihtiyaç duyulmadığında, Targetgörüntü ne olursa olsun işlenecek, böylece uzun ömürlü hedefler nedeniyle bellek sızıntılarıyla sıkışıp kalmayacaksınız, ancak Hedefiniz kalıcı olacaktır. Görüşü canlı olduğu sürece.


15
Günümü kurtardım. Teşekkürler.
cy198706

24
Resim görünümüm yok, o zaman bu sorunu nasıl çözebilirim? Bu tür durumlarla uğraşırken, gc en kötü düşmanınızdır
tim687

3
Hatta bir ArrayList <Hedef> 'de saklayabilirsiniz ve işe yarayacaktır, sadece o dizi listesini temizlemeyi unutmayın :-)
Oliver Dixon

2
OnBitmapLoaded ve onBitmapFailed'de, bitmap'i işledikten sonra imageView.setTag (null) da yapıyorum. Gerekli değil mi?
Jaguar

1
Teşekkür ederim! Hayatımı kurtardım :)
yusufiga

55

Picasso Hedef nesneye güçlü bir gönderme yapmaz, bu nedenle çöp toplanır ve onBitmapLoadedçağrılmaz.

Çözüm oldukça basit, sadece 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
Ya senin yapmak Viewuygulamak Target.
dnkoutso

belgelerde, geçersiz kılmanız Object.equals(Object)ve Object.hashCode()yöntemleri kullanmanız gerektiğini söylüyor . çalışan bir örnek var mı?
çip

nerede yazıyor? Hedefime () güçlü bir gönderme yapsam bile sorunum hala var.
psv

Şimdi okHttp'yi yükledim, yüklenmesi biraz daha hızlı ama yine de ilk çalıştırmada aynı sorunu yaşıyorum. Herhangi bir fikir ?
psv

@psv: Picasso'nun ilk başlatma sorununu çözdünüz mü? Bende de aynı sorun mu var? Çözdüyseniz nasıl çözdünüz?
TheDevMan

25

ImageView olsaydı şu şekilde basit bir şekilde yapardım: imageView.setTag (target);

Bitmap'leri bildirimlere yüklemek için sonraki çözümü kullanıyorum, bu yüzden sadece bitmap'e ihtiyacım var.

Bu nedenle, Set witch oluşturarak Hedef nesneleri depolar ve yükleme tamamlandığında kaldırır.

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
Benim sorunum da çözüldü. Bildirim ile kullanmak istedim. bazen görüntü Hedef ile indirilirken bazen indirilmiyordu. ancak ImageView'u kullandıktan sonra her
seferinde

1
benim durumumda, hepsi hariç, bu en iyi çözümdü!
Noor Hossain

4

Görünüm kullanmayanlar için çözüm burada. Bu yardımcı yöntem, bir sonuç döndürülene kadar hedef nesneyi geçici olarak depolamak için bir liste kullanır, böylece gc'd edilmez:

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'ın söylediği (ve alıntıladığı) gibi, Picasso'nun Hedef nesneye güçlü bir referansı yoktur. Çöp toplamadan kaçınmak için nesneye güçlü bir referans vermelisiniz.

Fetch () yöntemi hakkında. Belgelerde, fetch () 'in bir ImageView veya Target ile kullanılmayacağı oldukça açıktır, sadece önbelleği "ısıtmak" içindir ve başka bir şey değildir, bu yüzden onu istediğiniz şekilde kullanamayacaksınız. istemek.

@Lukas'ın açıkladığı gibi güçlü bir referans tutmanızı tavsiye ederim, işe yaramalı. Değilse lütfen projenin GitHub sayfasında yeni bir sayı açın.


3

Benzer bir sorunla karşılaştım ve hedefe referans tutmak hiç yardımcı olmadı, bu yüzden bir Bitmap döndüren aşağıdaki kodu kullandım:


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

aşağı tarafta -> geri arama yoktur ve bu işlevi ana iş parçacığında çağıramazsınız, bu işlevi aşağıdaki örnekte olduğu gibi bir arka plan iş parçacığı üzerinde çalıştırmanız gerekir:


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

Çok daha iyi çalışan bir başka şey de Glide kullanmaktır !

Projemin amacı, bir resim galerisi göstermek ve kullanıcıya hangi api'yi kullanacağını seçme olanağı vermek için 2 farklı resim indirme API'si kullanmak olduğu için her ikisini de kullanmam gerekiyordu.

Söylemeliyim ki, sonuçlara hayran kaldım, Glide'ın api'si her açıdan kusursuz çalıştı (Glide'ın hedefinin zayıf referansı yok) Picasso bana cehennem verdi (bu benim Glide'ı ilk kullanışımdı, şimdiye kadar genellikle Picasso kullandım, bugün değişecek gibi görünüyor ^^).


0

Ben de aynı sorunla karşılaşmıştım ancak aşağıda belirtildiği gibi bağımlılığı değiştirdiğimde artık düzgün çalışıyor.

 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'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.