onBitmapLoaded des Zielobjekts, das beim ersten Laden nicht aufgerufen wird

126

In meiner Funktion:

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 () wird beim ersten Laden von Bildern nie aufgerufen. Ich habe ein Thema wie https://github.com/square/picasso/issues/39 gelesen, das die Verwendung der Fetch-Methode (Target t) empfiehlt (es scheint ein Problem mit schwachen Referenzen zu sein ...), aber diese Funktion ist in der letzten Version von picasso (2.3.2) nicht verfügbar. Ich habe nur eine fetch () -Methode, kann sie aber nicht gleichzeitig in (mytarget) verwenden

Können Sie mir bitte erklären, wie man fetch () mit einem benutzerdefinierten Ziel verwendet? Danke dir.

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

psv
quelle
1
Stellen Sie sicher, dass Sie okhttp 2.0.0 verwenden. Bei der Verwendung von Picasso 2.3.2 mit Okhttp 1.6.0
hakim
github.com/square/okhttp afaik, es ist obligatorisch, wenn Sie Picasso 2.3.2 verwenden, um die okhttp- (und okio-) Bibliothek einzuschließen. Verwenden Sie Eclipse oder Android Studio?
Hakim
Ich benutze IntelliJ. Ich habe meine Gradle-Abhängigkeiten gesehen, ich habe okhttp nicht gesehen ... Picasso scheint ohne sie zu funktionieren
psv
@psv Wie haben Sie die folgende Lösung mit den Markern implementiert?
Mustafa Güven

Antworten:

247

Wie von den anderen Befragten (@lukas und @mradzinski) festgestellt, behält Picasso nur einen schwachen Bezug zum TargetObjekt. Während Sie eine starke Referenz Targetin einer Ihrer Klassen speichern können , kann dies dennoch problematisch sein, wenn die TargetReferenzen Viewin irgendeiner Weise a sind, da Sie effektiv auch eine starke Referenz darauf behalten View(was eines der Dinge ist, die Picasso ist hilft Ihnen ausdrücklich zu vermeiden).

Wenn Sie sich in dieser Situation befinden, würde ich empfehlen, das Targetmit dem Tag zu versehen View:

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

Dieser Ansatz hat den Vorteil, dass Picasso alles für Sie erledigt. Es verwaltet die WeakReferenceObjekte für jede Ihrer Ansichten - sobald eines nicht mehr benötigt wird, wird unabhängig von der TargetVerarbeitung des Bildes auch die Freigabe des Bilds freigegeben, sodass Sie nicht aufgrund langlebiger Ziele an Speicherlecks hängen bleiben, sondern Ihr Ziel bleibt erhalten solange seine Sicht lebt.

wrb
quelle
15
Hat meinen Tag gerettet. Vielen Dank.
Cy198706
24
Ich habe keine Bildansicht. Wie kann ich dieses Problem dann lösen? Wenn Sie mit solchen Situationen umgehen, ist der GC Ihr
schlimmster
3
Sie können es sogar in einer ArrayList <Ziel> speichern und es wird funktionieren. Denken Sie daran, diese Arrayliste zu löschen :-)
Oliver Dixon
2
In onBitmapLoaded und onBitmapFailed mache ich nach der Verarbeitung der Bitmap auch imageView.setTag (null). Wird es nicht benötigt?
Jaguar
1
Danke dir! Gerade mein Leben gerettet :)
Yusufiga
55

Picasso enthält keinen starken Verweis auf das Zielobjekt, daher wird der Müll gesammelt und onBitmapLoadednicht aufgerufen.

Die Lösung ist ganz einfach, verweisen Sie einfach stark auf die 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);
   }
}      
lukas
quelle
2
Oder machen Sie Ihr ViewGerät Target.
dnkoutso
in der Dokumentation, es sagt Sie außer Kraft zu setzen haben Object.equals(Object)und Object.hashCode()Methoden. Hast du eine Arbeitsprobe?
Chip
wo steht es geschrieben Ich habe immer noch mein Problem, auch wenn ich stark auf mein Ziel verweise ().
PSV
Ich habe jetzt okHttp installiert, es ist etwas schneller zu laden, aber ich habe immer noch das gleiche Problem beim ersten Start. Irgendwelche Ideen ?
PSV
@psv: Hast du das Problem mit dem ersten Start von Picasso gelöst? Ich habe das gleiche Problem? Wenn Sie gelöst haben, wie haben Sie es gelöst?
TheDevMan
25

Wenn ich ImageView hätte, würde ich einfach so machen: imageView.setTag (Ziel);

Ich verwende die nächste Lösung zum Laden von Bitmaps in Benachrichtigungen, daher benötige ich nur Bitmap.

Erstellen Sie also Set, in dem Zielobjekte gespeichert und nach dem Laden entfernt werden.

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

        }
    }
Flinbor
quelle
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() {

            }
        });
Raghav Satyadev
quelle
1
Es hat auch mein Problem gelöst. Ich wollte es mit Benachrichtigung verwenden. Manchmal wurde das Bild mit Target heruntergeladen und manchmal nicht. aber nachdem ich ImageView benutzt hatte, konnte ich
jedes Mal
1
In meinem Fall war dies mit Ausnahme aller die beste Lösung!
Noor Hossain
4

Hier ist die Lösung für diejenigen, die keine Ansicht verwenden. Diese Hilfsmethode verwendet eine Liste, um das Zielobjekt vorübergehend zu speichern, bis ein Ergebnis zurückgegeben wird, damit es nicht gc'd wird:

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);
}
DroidT
quelle
3

Wie @lukas sagte (und zitierte), enthält Picasso keinen starken Verweis auf das Zielobjekt. Um eine Speicherbereinigung zu vermeiden, müssen Sie einen starken Verweis auf das Objekt enthalten.

Informationen zur Methode fetch (). In der Dokumentation ist ziemlich klar, dass fetch () weder mit einer ImageView noch mit einem Target verwendet werden darf, sondern nur, um den Cache "aufzuwärmen" und sonst nichts, sodass Sie ihn nicht so verwenden können, wie Sie es möchten wollen.

Ich empfehle Ihnen, eine starke Referenz zu haben, wie @lukas erklärt hat, es sollte funktionieren. Wenn nicht, öffnen Sie bitte eine neue Ausgabe auf der GitHub-Seite des Projekts.

mradzinski
quelle
3

Ich bin auf ein ähnliches Problem gestoßen, und das Verweisen auf das Ziel hat überhaupt nicht geholfen. Daher habe ich den folgenden Code verwendet, der eine Bitmap zurückgibt:


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

auf der anderen Seite -> es gibt keinen Rückruf und Sie können diese Funktion nicht im Hauptthread aufrufen. Sie müssen diese Funktion in einem Hintergrundthread wie im folgenden Beispiel ausführen:


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

Eine andere Sache, die viel besser funktioniert, ist die Verwendung von Glide!

Ich musste beide verwenden, da der Zweck meines Projekts darin bestand, zwei verschiedene Bild-Download-APIs zu verwenden, um eine Bildergalerie anzuzeigen und dem Benutzer die Möglichkeit zu geben, die zu verwendende API auszuwählen.

Ich muss sagen, ich war erstaunt über die Ergebnisse, Glides API hat in jeder Hinsicht einwandfrei funktioniert (Glides Ziel hat keinen schwachen Bezug), während Picasso mir die Hölle gab (das war mein erstes Mal mit Glide, ich habe bisher normalerweise Picasso verwendet). scheint sich heute zu ändern ^^).

Roee
quelle
0

Ich hatte das gleiche Problem, aber wenn ich die Abhängigkeit wie unten erwähnt ändere, funktioniert sie jetzt ordnungsgemäß.

 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'
Khushbu
quelle