Dans ma fonction:
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);
}
Le onBitmapLoaded () n'est jamais appelé la première fois que je charge des images. J'ai lu des sujets comme https://github.com/square/picasso/issues/39 qui recommandent d'utiliser la méthode fetch (Target t) (cela semble être un problème de référence faible. ..), mais cette fonction n’est pas disponible dans la dernière version de picasso (2.3.2). J'ai seulement une méthode fetch (), mais je ne peux pas utiliser (mytarget) en même temps
Pourriez-vous m'expliquer comment utiliser fetch () avec une cible personnalisée, s'il vous plaît? Je vous remercie.
Doc: http://square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--
Comme l'ont noté les autres répondants (@lukas et @mradzinski), Picasso ne conserve qu'une faible référence à l'objet Target
. Bien que vous puissiez stocker une référence forte Target
dans l'une de vos classes, cela peut toujours être problématique si Target
fait référence à View
de quelque manière que ce soit, car vous aurez également gardez également une référence forte à ce View
(ce qui est une des choses que Picasso vous a explicitement évité).
Si vous êtes dans cette situation, je vous conseillerais de taguer le Target
au View
:
final ImageView imageView = ... // The view Picasso is loading an image into
final Target target = new Target{...};
imageView.setTag(target);
Cette approche a l'avantage de laisser Picasso gérer tout pour vous. Il gérera les objets WeakReference
pour chacune de vos vues - dès que vous n'en aurez plus besoin, quel que soit le traitement de Target
, l'image sera également publiée, vous évitant ainsi des fuites de mémoire. en raison de cibles à long terme, mais votre cible durera tant que sa vue restera active.
Picasso ne contient pas de référence forte à l’objet Cible. Il est donc collecté et l’onBitmapLoaded n’est pas appelé.
La solution est simple, il suffit de faire une référence forte à la cible.
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);
}
}
Si j'avais ImageView, je ferais simplement ceci: imageView.setTag (cible);
J'utilise la solution suivante pour charger des bitmaps dans les notifications, je n'ai donc besoin que de bitmap.
Alors, créez Set qui stockera les objets cibles et les supprimera à la fin du chargement.
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) {
}
}
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() {
}
});
Voici la solution pour ceux qui n'utilisent pas de vue. Cette méthode d'assistance utilise une liste pour stocker temporairement l'objet cible jusqu'à ce qu'un résultat soit renvoyé afin qu'il ne soit pas généré:
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(Drawable errorDrawable) {
targets.clear();
callback.onFailure(null);
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
targets.add(target);
Picasso.with(context).load(url).into(target);
}
Comme @lukas a dit (et citant), Picasso ne détient pas de forte référence à l'objet cible. Pour éviter la récupération de place, vous devez tenir une référence forte à l'objet.
A propos de la méthode fetch (). Il est assez clair dans la documentation que fetch () ne doit pas être utilisé avec une ImageView ni une cible, c'est juste pour "réchauffer" le cache et rien d'autre, pour que vous ne puissiez pas l'utiliser comme vous le feriez vouloir.
Je vous recommande de tenir une référence forte comme @lukas a expliqué, cela devrait fonctionner. Sinon, ouvrez un nouveau numéro sur la page GitHub du projet.
J'ai rencontré un problème similaire et le maintien de la référence à la cible n'a pas aidé du tout, alors j'ai utilisé le code suivant qui renvoie un bitmap:
Bitmap bitmap = picasso.with(appContext).load(url).get();
côté négatif -> il n'y a pas de rappel et vous ne pouvez pas appeler cette fonction sur le thread principal, vous devez l'exécuter sur un thread d'arrière-plan, comme dans l'exemple suivant:
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);
}
}
}
});
Une autre chose qui fonctionne beaucoup mieux est simplement d'utiliser Glide!
Je devais utiliser les deux car l'objectif de mon projet était d'utiliser deux api de téléchargement d'images différentes pour montrer une galerie d'images et permettre à l'utilisateur de choisir quelle api utiliser.
Je dois dire que les résultats m'ont impressionné. L'API de Glide a parfaitement fonctionné (la cible de Glide n'a pas de références faibles). on dirait qu'aujourd'hui ça va changer ^^).