web-dev-qa-db-ja.com

最初のロード時に呼び出されないTargetオブジェクトのonBitmapLoaded

私の機能では:

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)メソッドを使用することをお勧めします(弱参照の問題のようです。 ..)、ただし、この関数はpicasso(2.3.2)の最後のリリースでは使用できません。 fetch()メソッドしかありませんが、into(mytarget)を同時に使用することはできません

カスタムターゲットでfetch()を使用する方法を教えてください。ありがとうございました。

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

120
psv

他の回答者(@lukasおよび@mradzinski)が指摘しているように、ピカソはTargetオブジェクトへの弱い参照のみを保持しています。強参照Targetをクラスの1つに格納できますが、Targetが何らかの方法でViewを参照している場合、これは依然として問題になる可能性があります。そのViewへの強い参照(これは、Picassoが明示的に回避するのに役立つことの1つです)。

このような場合は、TargetViewにタグ付けすることをお勧めします。

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

このアプローチには、Picassoがすべてを処理できるという利点があります。ビューごとにWeakReferenceオブジェクトを管理します。ビューが不要になるとすぐに、画像のTarget処理も解放されるため、メモリリークに悩まされることはありません。存続期間の長いターゲットですが、ターゲットが表示されている限りターゲットは存続します。

234
wrb

PicassoはTargetオブジェクトへの強力な参照を保持していないため、ガベージコレクションされ、onBitmapLoadedは呼び出されません。

解決策は静かでシンプルです。ターゲットを強く参照してください。

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

ImageViewがあれば、次のように簡単に作成できます。imageView.setTag(target);

次のソリューションを使用して、ビットマップを通知にロードするため、ビットマップのみが必要です。

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

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

            }
        });
12
Raghav Satyadev

これは、ビューを使用していない人向けのソリューションです。このヘルパーメソッドはリストを使用して、結果が返されるまでターゲットオブジェクトを一時的に保存し、GCされないようにします。

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

@lukasが言ったように(引用して)、ピカソはTargetオブジェクトへの強い参照を保持していません。ガベージコレクションを回避するには、オブジェクトへの強い参照を保持する必要があります。

Fetch()メソッドについて。ドキュメントでは、fetch()がImageViewまたはTargetで使用されるべきではなく、キャッシュを「ウォームアップ」するだけで、それ以外は何もしないので、あなたはそれをあなたの方法で使用することはできません欲しいです。

@lukasのような強力なリファレンスを保持することをお勧めします。そうでない場合は、プロジェクトのGitHubページで新しい問題を開いてください。

3
mradzinski

私は同様の問題に遭遇し、ターゲットへの参照を保持してもまったく役に立ちませんでしたので、ビットマップを返す次のコードを使用しました:


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

下側->コールバックはなく、この関数をメインスレッドで呼び出すことはできません。次の例のように、この関数をバックグラウンドスレッドで実行する必要があります。


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を選択できるようにすることであるため、両方を使用する必要がありました。

私は言わなければならない、私はピカソが地獄を与えてくれたので、グライドのAPIはあらゆる面で完璧に働いた(グライドのターゲットは弱い参照を持っていません)今日は変更されるようです^^)。

3
Roee