onBitmapLoaded dari objek Target tidak dipanggil saat memuat pertama

126

Dalam fungsi saya:

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 () tidak pernah disebut pertama kali saya memuat gambar. Saya telah membaca beberapa topik seperti https://github.com/square/picasso/issues/39 yang merekomendasikan untuk menggunakan metode fetch (Target t) (sepertinya merupakan masalah referensi lemah ...), tetapi fungsi ini tidak tersedia dalam rilis terakhir picasso (2.3.2). Saya hanya memiliki metode fetch (), tetapi saya tidak dapat menggunakan (mytarget) pada saat yang sama

Bisakah Anda menjelaskan kepada saya bagaimana cara menggunakan fetch () dengan Target kustom? Terima kasih.

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

psv
sumber
1
pastikan untuk menggunakan okhttp 2.0.0, saya menemukan masalah yang sama saat menggunakan Picasso 2.3.2 dengan Okhttp 1.6.0
hakim
github.com/square/okhttp afaik, wajib jika Anda menggunakan Picasso 2.3.2 untuk memasukkan pustaka okhttp (dan okio). apakah Anda menggunakan gerhana atau studio android?
hakim
Saya menggunakan IntelliJ. Saya telah melihat dependensi gradle saya, saya tidak melihat okhttp ... Picasso tampaknya bekerja tanpanya
psv
@psv bagaimana Anda menerapkan solusi di bawah ini dengan spidol?
Mustafa Güven

Jawaban:

247

Seperti dicatat oleh responden lain (@lukas dan @mradzinski), Picasso hanya menyimpan referensi yang lemah ke Targetobjek. Meskipun Anda dapat menyimpan referensi yang kuat Targetdi salah satu kelas Anda, ini masih bisa menjadi masalah jika Targetreferensi tersebut dengan Viewcara apa pun, karena Anda juga akan secara efektif menyimpan referensi yang kuat untuk itu Viewjuga (yang merupakan salah satu hal yang Picasso secara eksplisit membantu Anda menghindari).

Jika Anda berada dalam situasi ini, saya sarankan memberi tag Targetke View:

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

Pendekatan ini bermanfaat membiarkan Picasso menangani semuanya untuk Anda. Ini akan mengelola WeakReferenceobjek untuk setiap tampilan Anda - segera setelah satu tidak diperlukan lagi, Targetpemrosesan apa pun gambar juga akan dirilis, sehingga Anda tidak terjebak dengan kebocoran memori karena target jangka panjang, tetapi Target Anda akan bertahan selama pandangannya hidup.

wrb
sumber
15
Menyelamatkan hariku. Terima kasih.
cy198706
24
Saya tidak memiliki tampilan gambar, bagaimana saya bisa menyelesaikan masalah ini? Ketika berhadapan dengan situasi seperti ini, gc adalah musuh terburuk Anda
tim687
3
Anda bahkan dapat menyimpannya di ArrayList <Target> dan itu akan berhasil, ingatlah untuk menghapus arraylist itu :-)
Oliver Dixon
2
Di onBitmapLoaded dan onBitmapFailed, saya juga melakukan imageView.setTag (null) setelah memproses bitmap. Apakah itu tidak dibutuhkan?
Jaguar
1
Terima kasih! Baru saja menyelamatkan hidupku :)
yusufiga
55

Picasso tidak memiliki referensi yang kuat ke objek Target, sehingga menjadi sampah yang dikumpulkan dan onBitmapLoadedtidak dipanggil.

Solusinya cukup sederhana, cukup buat referensi kuat ke 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);
   }
}      
lukas
sumber
2
Atau membuat Anda Viewmenerapkan Target.
dnkoutso
dalam dokumen, dikatakan Anda harus mengganti Object.equals(Object)dan Object.hashCode()metode. apakah Anda memiliki sampel yang berfungsi?
chip
dimana itu tertulis? Saya masih memiliki masalah bahkan dengan membuat referensi yang kuat ke Target saya ().
psv
Saya sekarang telah menginstal okHttp, ini sedikit lebih cepat untuk memuat tetapi saya masih memiliki masalah yang sama pada peluncuran pertama. Ada ide?
psv
@psv: Apakah Anda bisa memecahkan masalah peluncuran picasso pertama? Saya memiliki masalah yang sama? Jika Anda telah memecahkan bagaimana Anda menyelesaikannya?
TheDevMan
25

Jika saya memiliki ImageView, saya akan membuatnya seperti ini: imageView.setTag (target);

Saya menggunakan solusi berikutnya untuk memuat Bitmap ke notifikasi, jadi saya hanya perlu bitmap.

Jadi buat Set witch akan menyimpan objek Target dan menghapusnya saat selesai memuat.

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

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

            }
        });
Raghav Satyadev
sumber
1
Ini memecahkan masalah saya juga. saya ingin menggunakannya dengan Pemberitahuan. terkadang gambar diunduh dengan Target dan terkadang tidak. tetapi setelah menggunakan ImageView saya dapat memuat gambar setiap saat
Raveesh GS
1
dalam kasus saya, kecuali semua, ini adalah solusi terbaik!
Noor Hossain
4

Berikut adalah solusi untuk mereka yang tidak menggunakan tampilan. Metode helper ini menggunakan daftar untuk menyimpan sementara objek target hingga hasilnya dikembalikan sehingga tidak 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(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);
}
DroidT
sumber
3

Seperti kata @ lukas (dan mengutip), Picasso tidak memiliki referensi yang kuat ke objek Target. Untuk menghindari pengumpulan sampah, Anda harus memiliki referensi kuat ke objek.

Tentang metode fetch (). Cukup jelas dalam dokumentasi bahwa fetch () tidak dapat digunakan dengan ImageView atau Target, hanya untuk "menghangatkan" cache dan tidak ada yang lain, jadi Anda tidak akan dapat menggunakannya dengan cara yang Anda inginkan. ingin.

Saya sarankan Anda memegang referensi kuat seperti @ lukas menjelaskan, itu harus bekerja. Jika tidak, silakan buka masalah baru di halaman GitHub proyek.

mradzinski
sumber
3

Saya mengalami masalah serupa dan menahan referensi ke target tidak membantu sama sekali jadi saya menggunakan kode berikut yang mengembalikan Bitmap:


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

di sisi bawah -> tidak ada panggilan balik dan Anda tidak dapat memanggil fungsi ini di utas utama, Anda harus menjalankan fungsi ini pada utas latar belakang seperti pada contoh berikut:


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

Hal lain yang jauh lebih baik adalah menggunakan Glide!

Saya perlu menggunakan keduanya karena tujuan dari proyek saya adalah menggunakan 2 api unduhan gambar yang berbeda untuk menampilkan galeri gambar dan memberi pengguna kemampuan untuk memilih api mana yang akan digunakan.

Saya harus mengatakan, saya kagum dengan hasilnya, api Glide bekerja dengan sempurna di setiap aspek (target Glide tidak memiliki referensi yang lemah) ketika Picasso memberi saya neraka (itu adalah pertama kalinya saya menggunakan Glide, saya biasanya menggunakan Picasso sejauh ini, sepertinya hari ini akan berubah ^^).

Roee
sumber
0

Saya telah menghadapi masalah yang sama tetapi ketika saya mengubah ketergantungan seperti yang disebutkan di bawah, Ini berfungsi dengan baik sekarang.

 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'
khushbu
sumber