在第一次加载时未调用的Target对象的onBitmapLoaded

psv*_*psv 122 picasso

在我的功能:

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);
}
Run Code Online (Sandbox Code Playgroud)

我第一次加载图片时从不调用onBitmapLoaded().我已经阅读了一些话题,如https://github.com/square/picasso/issues/39,建议使用fetch(Target t)方法(这似乎是弱引用的问题......),但是这个函数在毕加索的最后一个版本(2.3.2)中没有.我只有一个fetch()方法,但我不能同时使用(mytarget)

你能解释一下如何使用fetch()和自定义Target吗?谢谢.

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

wrb*_*wrb 237

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

如果您处于这种情况,我建议将标记标记TargetView:

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

这种方法的好处是让毕加索能够为您处理一切.它将管理WeakReference每个视图的对象 - 只要不再需要一个,Target对图像也将被释放的任何处理,所以你不会因长期目标而陷入内存泄漏,但你的目标会持续只要它的观点还活着.

  • 我没有图像视图,那我怎么解决这个问题呢?在处理这种情况时,gc是你最糟糕的敌人 (21认同)
  • 救了我的一天.谢谢. (13认同)
  • 你甚至可以将它存储在ArrayList <Target>中,它会工作,只记得清除那个arraylist :-) (2认同)
  • 在onBitmapLoaded和onBitmapFailed中,我在处理位图后也在做imageView.setTag(null).不需要吗? (2认同)

luk*_*kas 54

Picasso没有对Target对象的强引用,因此它被垃圾收集并且不调用onBitmapLoaded.

解决方案很简单,juste强烈引用了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);
   }
}      
Run Code Online (Sandbox Code Playgroud)

  • 或者让你的`View`实现`Target`. (2认同)

Fli*_*bor 22

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

我使用下一个解决方案将Bitmaps加载到通知中,所以我只需要位图.

因此,创建Set witch将存储Target对象并在完成加载时将其删除.

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

        }
    }
Run Code Online (Sandbox Code Playgroud)


Rag*_*dev 12

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

            }
        });
Run Code Online (Sandbox Code Playgroud)


Roe*_*oee 6

我遇到了类似的问题,并且保留对目标的引用根本没有帮助,因此我使用了以下返回位图的代码:


Bitmap bitmap = picasso.with(appContext).load(url).get();
Run Code Online (Sandbox Code Playgroud)

缺点-> 没有回调,您无法在主线程上调用此函数,您必须在后台线程上运行此函数,如下例所示:


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);
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

另一件效果更好的事情就是使用Glide!

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

我不得不说,我对结果感到惊讶,Glide 的 api 在各个方面都完美地工作(Glide 的目标没有弱引用),而 Picasso 给了我地狱(这是我第一次使用 Glide,到目前为止我通常使用 Picasso,看来今天要改变了^^)。


Dro*_*idT 5

这是那些不使用视图的人的解决方案。这个辅助方法使用一个列表来临时存储目标对象,直到返回结果,这样它就不会被 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);
}
Run Code Online (Sandbox Code Playgroud)