使用Picasso获取Bitmap回调函数

88

我正在使用Picasso在我的应用程序中下载图像。

我处于一种需要在ImageView加载位图之前先访问Bitmap的情况下。 Downloader.Response类的存在似乎表明这是可能的,但我找不到任何使用示例。如果可以使用Picasso完成此特定情况,我就不想编写大量其他代码来异步处理它。

有人能展示给我如何做吗?


https://dev59.com/hYPba4cB1Zd3GeqPup1q#36310327 - Shubham AgaRwal
4个回答

177

如果有人想知道,我在 Github 上找到了答案:

private Target target = new Target() {
      @Override
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
      }

      @Override
      public void onBitmapFailed(Drawable errorDrawable) {
      }

      @Override
      public void onPrepareLoad(Drawable placeHolderDrawable) {
      }
}

private void someMethod() {
   Picasso.with(this).load("url").into(target);
}

@Override 
public void onDestroy() {  // could be in onPause or onStop
   Picasso.with(this).cancelRequest(target);
   super.onDestroy();
}

该文章建议不要使用匿名回调函数,而是使用实例变量来代替目标。


31
理想情况下,您可以直接在视图或视图持有者对象上实现 Target 接口。如果您没有这样做,您需要在某个地方维护该实例的强引用,否则它将被垃圾回收。 - Jake Wharton
@JakeWharton:如果我想在 ListView 的每个项目上应用自定义动画,您建议做类似这样的事情:private static ViewHolder { private ImageView imageView; private Target target = new Target() { public void onBitmapLoaded() { // 在 imageView 上执行动画 } } } - mbmc
8
在调用onPrepareLoad后,第一次调用onBitmapLoaded可能会失败。 - Amit Thaper
谢谢提供示例。我只是在onDestroy中缺少一个super调用。 - Ben Groot
使用目标会绕过PicassoDrawable完成的漂亮的alpha动画。我想保留这种行为,并同时获取位图,以添加一个由Palette API生成的颜色叠加层。有什么办法可以做到这一点吗? - mbonnin
显示剩余4条评论

74

摘自此处

Picasso.with(this)
    .load(url)
    .into(new Target() {
        @Override
        public void onBitmapLoaded (final Bitmap bitmap, Picasso.LoadedFrom from){
            /* Save the bitmap or do something with it here */

            //Set it in the ImageView
            theView.setImageBitmap(bitmap); 
        }
});

更新(2016年5月4日):

            Picasso.with(this)
                .load(youUrl)
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {

                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {

                    }
                });

更新日期(2016年11月22日)

或者对Target使用强引用,以防它被垃圾收集器回收。

Target target = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };


void foo() {
        Picasso.with(getContext()).load(getUrl()).into(target);
}

Kotlin
object: com.squareup.picasso.Target {
                  override fun onBitmapFailed(e: java.lang.Exception?, errorDrawable: Drawable?) {
                    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                }

                  override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
                    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                  }

                  override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {

                  }
                }

6
匿名目标可能会被垃圾回收。 - Steve M
@SteveM 那会做什么?取消请求?防止位图被加载? - nurettin
所以这个解决方案真的很糟糕,因为垃圾回收可能会在加载和调用回调之间偶尔运行,并导致回调不被调用。 - Steve M
@SteveM 感谢您提出的观点,我已经更新了应用程序以防万一。 - nurettin
对于 Kotlin,它需要是 'onBitmapFailed(e: Exception, errorDrawable: Drawable?)'。 - user5669940
显示剩余3条评论

11

还有什么比这更容易的呢:

val url: String = "https://...."
val bitmap: Bitmap = Picasso.with(context).load(url).get()

应该在非主线程调用!

或者使用 RxJava 2:

fun getBitmapSingle(picasso: Picasso, url: String): Single<Bitmap> = Single.create {
    try {
        if (!it.isDisposed) {
            val bitmap: Bitmap = picasso.load(url).get()
            it.onSuccess(bitmap)
        }
    } catch (e: Throwable) {
        it.onError(e)
    }
}

获取位图:

getBitmapSingle(Picasso.with(context), "https:/...")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ bitmap ->
                // val drawable = BitmapDrawable(context, bitmap)
                }, Throwable::printStackTrace)

我使用的是Picasso v.2.5.2


2

我想有些人可能需要以上答案的RxJava版本...在这里:

    public static Observable<Bitmap> loadBitmap(Picasso picasso, String imageUrl) {
    return Observable.create(new Observable.OnSubscribe<Bitmap>() {
        @Override
        public void call(Subscriber<? super Bitmap> subscriber) {
            Target target = new Target() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                    subscriber.onNext(bitmap);
                    subscriber.onCompleted();
                }

                @Override
                public void onBitmapFailed(Drawable errorDrawable) {
                    subscriber.onError(new Exception("failed to load " + imageUrl));
                }

                @Override
                public void onPrepareLoad(Drawable placeHolderDrawable) {
                }
            };
            subscriber.add(new Subscription() {
                private boolean unSubscribed;

                @Override
                public void unsubscribe() {
                    picasso.cancelRequest(target);
                    unSubscribed = true;
                }

                @Override
                public boolean isUnsubscribed() {
                    return unSubscribed;
                }
            });
            picasso.load(imageUrl).into(target);
        }
    });
}

P.S. 订阅时,请在您的活动中存储订阅参考,否则,在您收到响应之前,目标对象将被GC'd(垃圾回收)...


似乎这段代码现在无法与最新的RxAndroid一起使用。 - Pavandroid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接