在第一次加载时不调用目标对象的onBitmapLoaded

在我的function:

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这样的主题,其中推荐使用fetch(Target t)方法(这似乎是一个弱引用的问题…),但是这个函数(2.3.2)的最后版本中不可用。 我只有一个fetch()方法,但是我不能同时使用(mytarget)

你能解释我如何使用fetch()与一个自定义的目标吗? 谢谢。

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

正如其他受访者(@lukas和@mradzinski)所指出的那样,毕加索只是对Target客体保持一个薄弱的提法。 虽然你可以在你的类中存储一个强大的引用Target ,但是如果Target以任何方式引用一个View ,这仍然是有问题的,因为你也将有效地保持对该View的强大引用(这是毕加索明确帮助你避免的事情)。

如果你在这种情况下,我build议将Target标记到View

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

这种方法有利于让毕加索为您处理所有事情。 它会pipe理你的每个视图的WeakReference对象 – 一旦不再需要,无论Target处理的图像也将被释放,所以你不会因为长时间的目标卡住内存泄漏,但你的目标将持续下去,只要它的观点还活着。

毕加索对目标对象没有强烈的引用,因此它被垃圾收集,onBitmapLoaded不被调用。

解决scheme简单安静,正好对目标做出了很好的参考。

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

如果我有ImageView,我会简单地这样做:imageView.setTag(target);

我使用下一个解决scheme将Bitmap加载到通知中,所以我只需要位图。

所以创buildSet巫师将存储目标对象,并在完成加载时删除它们。

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

就像@卢卡斯所说(引用),毕加索并没有强烈地提到目标对象。 为了避免垃圾收集,你必须持有对该对象的强烈的引用。

关于fetch()方法。 在文档中很明显,fetch()不能用于ImageView或Target,只是为了“缓冲”caching而没有别的,所以你不能像你一样使用它想。

我build议你持有像卢卡斯解释说的强大的参考,它应该工作。 如果没有,请在项目的GitHub页面上打开一个新的问题。

我遇到类似的问题,并持有引用的目标没有帮助,所以我用下面的代码返回一个位图:


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

在下面 – >没有callback,你不能在主线程上调用这个函数,你必须在后台线程上运行这个函数,如下例所示:


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

另外一个更好的方法就是使用Glide!

我需要使用它们,因为我的项目的目的是使用2个不同的图像下载api来显示图像库,并让用户能够select使用哪个api。

我不得不说,我对结果感到惊讶,Glide的api在每个方面都完美无缺地工作(Glide的目标没有太多的参考),但是毕加索给了我地狱(这是我第一次使用Glide,我通常使用毕加索到目前为止,看起来像今天它会改变^^)。