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

时间:2014-06-12 09:22:28

标签: 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);
}

我第一次加载图片时从不调用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--

8 个答案:

答案 0 :(得分:233)

正如其他受访者(@lukas和@mradzinski)所指出的,毕加索只保留对Target对象的弱引用。虽然您可以在其中一个类中存储强引用Target,但如果Target以任何方式引用View,这仍然会有问题,因为您实际上也会保留一个View强烈提及Target(这是毕加索明确帮助你避免的事情之一)。

如果您遇到这种情况,我建议您将View标记为final ImageView imageView = ... // The view Picasso is loading an image into final Target target = new Target{...}; imageView.setTag(target);

WeakReference

这种方法的好处是让毕加索能为您处理一切。它将管理每个视图的Target个对象 - 只要不再需要一个,无论{{1}}处理图像也将被释放,因此您不会因为内存泄漏而陷入困境长期目标,但你的目标将持续只要它的视野还活着。

答案 1 :(得分:54)

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

解决方案很简单,juste强烈引用目标。

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 :(得分:21)

如果我有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) {

        }
    }

答案 3 :(得分: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() {

            }
        });

答案 4 :(得分:3)

就像@lukas所说(和引用)一样,毕加索并没有对Target对象有强烈的引用。为避免垃圾回收,您必须拥有对该对象的强引用。

关于fetch()方法。在文档中很清楚fetch()不能与ImageView和Target一起使用,它只是“加热”缓存而不是其他任何东西,所以你不能像你一样使用它想。

我建议你持有像@lukas这样强有力的参考解释,它应该有效。如果没有,请在项目的GitHub页面上打开一个新问题。

答案 5 :(得分:3)

我遇到了类似的问题,并且对目标的引用没有任何帮助,所以我使用下面的代码返回一个Bitmap:

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

缺点 - &gt;没有回调,你不能在主线程上调用这个函数,你必须在a上运行这个函数 后台线程如下例所示:

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来显示图像库并让用户能够选择使用哪个api。

我不得不说,我对结果感到惊讶,Glide的api在各个方面都完美无缺(Glide的目标没有弱参考),毕加索给了我地狱(这是我第一次使用Glide,我通常使用Picasso到目前为止,似乎今天它会改变^^)。

答案 6 :(得分:3)

以下是未使用视图的解决方案。这个帮助器方法使用一个列表来临时存储目标对象,直到返回一个结果,这样它就不是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(Drawable errorDrawable) {
            targets.clear();
            callback.onFailure(null);
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
        }
    };
    targets.add(target);
    Picasso.with(context).load(url).into(target);
}

答案 7 :(得分:0)

我曾经遇到过同样的问题,但是当我按如下所述更改依赖关系时,它现在可以正常工作。

 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'