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


126

私の機能では:

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()を使用する方法を教えてください。ありがとうございました。

ドキュメント:http : //square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--


1
okhttp 2.0.0を必ず使用してください。Okhttp1.6.0でPicasso 2.3.2を使用すると同じ問題が発生します
hakim

github.com/square/okhttp afaik、Picasso 2.3.2を使用してokhttp(およびokio)ライブラリを含める場合は必須です。EclipseまたはAndroid Studioを使用していますか?
ハキム2014年

IntelliJを使用しています。Gradleの依存関係を確認しましたが、okhttpは確認できませんでした...ピカソはそれなしでも動作するようです
psv

@psvマーカーを使用して以下のソリューションをどのように実装しましたか?
ムスタファグベン

回答:


247

他の回答者(@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、イメージの処理も解放されます。そのため、長期間有効なターゲットによるメモリリークに悩まされることはありませんが、ターゲットは持続しますその見方が生きている限り。


15
私の日を救った。ありがとう。
cy198706 2015年

24
画像ビューを持っていない場合、どうすればこの問題を解決できますか?このような状況に対処する場合、
GC

3
ArrayList <Target>に格納することもでき、機能します。そのarraylistをクリアすることを忘れないでください:-)
Oliver Dixon

2
onBitmapLoadedとonBitmapFailedでは、ビットマップの処理後にimageView.setTag(null)も実行しています。必要ありませんか?
ジャガー

1
ありがとうございました!ちょうど私の命を救った:)
yusufiga

55

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

解決策は非常に単純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);
   }
}      

2
またはあなたが作るView実装しますTarget
dnkoutso 14

ドキュメントではObject.equals(Object)Object.hashCode()メソッドとメソッドをオーバーライドする必要があると書かれています。実用的なサンプルはありますか?
チップ

どこに書いてあるの?Target()を強く参照しても、まだ問題があります。
psv 2014

これでokHttpをインストールしました。ロードは少し高速ですが、最初の起動時にも同じ問題が発生します。何か案は ?
psv 2014

@psv:ピカソの最初の起動に関する問題を解決しましたか?私は同じ問題を抱えています?解決した場合、どのように解決しましたか?
TheDevMan

25

ImageViewがある場合は、次のように簡単に作成します。imageView.setTag(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) {

        }
    }

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

            }
        });

1
私の問題も解決しました。通知で使用したかった。Targetで画像がダウンロードされる場合とそうでない場合があります。しかし、ImageViewを使用した後は、毎回画像を読み込むことができました
Raveesh GS

1
私の場合、すべてを除いて、これが最善の解決策でした!
Noor Hossain

4

これは、ビューを使用していない人のためのソリューションです。このヘルパーメソッドは、リストを使用して、結果が返されて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(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);
}

3

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

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

@lukasが説明するように、強い参照を保持することをお勧めします。そうでない場合は、プロジェクトのGitHubページで新しい問題を開いてください。


3

同様の問題が発生し、ターゲットへの参照を保持することはまったく役に立たなかったため、ビットマップを返す次のコードを使用しました。


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

全体的によく機能するもう1つのことは、Glideを使用することです!

私のプロジェクトの目的は2つの異なる画像ダウンロードAPIを使用して画像ギャラリーを表示し、使用するAPIをユーザーが選択できるようにすることだったので、両方を使用する必要がありました。

私は結果に驚かされました、Glideのapiはあらゆる面で完璧に機能しました(Glideのターゲットには弱い参照がありません)wile Picassoは私に地獄を与えました今日のように見えます^^)。


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'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.