使用 Picasso 获取带有位图的回调

Posted

技术标签:

【中文标题】使用 Picasso 获取带有位图的回调【英文标题】:Use Picasso to get a callback with a Bitmap 【发布时间】:2013-12-09 11:53:32 【问题描述】:

我正在使用 Picasso 为我的应用下载图像。

我需要先访问Bitmap,然后才能将其加载到ImageViewDownloader.Response 类的存在似乎表明这是可能的,但我找不到任何使用示例。如果可以使用毕加索,我不想编写更多代码来异步处理这个特殊情况。

谁能告诉我怎么做?

【问题讨论】:

***.com/a/36310327/5028508 【参考方案1】:

如果有人想知道,请在 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();

帖子建议不要使用匿名回调,而是使用实例变量作为目标。

【讨论】:

理想情况下,您应该直接在视图或视图持有者对象上实现Target。如果您不这样做,则需要在某处维护对实例的强引用,否则它将被垃圾收集。 @JakeWharton:如果我想在ListView 的每个项目上应用自定义动画,你建议这样做:private static ViewHolder private ImageView imageView; private Target target = new Target() public void onBitmapLoaded() // do animation on imageView ? @JakeWharton 在最后一条评论中在这里github.com/square/picasso/issues/308 解释。 onBitmapLoaded onPrepareLoad 后第一次不调用 感谢您的示例。我只是错过了 onDestroy 中的一个超级调用。【参考方案2】:

取自here:

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

科特林

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

                  
                

【讨论】:

匿名目标可能被垃圾回收 @SteveM 那会做什么?取消请求?防止加载位图? @nurettin 我假设毕加索(或 Glide)对目标有某种弱引用。因此,如果它是匿名的,则没有硬引用,并且容易受到 GC 的攻击。当 Picasso 检查引用时,它将为 null,因此不会调用回调。 所以这个解决方案真的很糟糕,因为GC可能偶尔会在回调的加载和调用之间运行,导致回调不被调用。 @SteveM 我在 google play 上托管了一个应用程序,该应用程序在其列表视图滚动期间加载一堆图标,在任何情况下至少有 2000 个用户,使用这种方法缩放一些图标,但我没有没有看到任何关于图标未加载的投诉、评论(我收到很多)或崩溃报告。所以至少有趣的是,由于某种原因,它没有收集垃圾。【参考方案3】:

比下一个更容易:

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

【讨论】:

【参考方案4】:

我想也许你们中的一些人想要上述答案的 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);
        
    );

附:订阅时,将订阅引用存储在您的活动中,否则,目标将在您收到响应之前被 GC...

【讨论】:

似乎这段代码现在不适用于最新的 RxAndroid

以上是关于使用 Picasso 获取带有位图的回调的主要内容,如果未能解决你的问题,请参考以下文章

在 AsyncTask 中使用 Picasso 从 URL 获取位图

当应用程序未运行时,无法在 intentservice 上使用 Picasso 目标获取图像位图

Picasso使用Target无法回调的分析与解决

Picasso使用Target无法回调的分析与解决

使用 Picasso 和 OkHttp 更新/更改缓存位图

使用 Picasso 和 minifyEnabled 时应用程序崩溃 true