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ซึ่งแนะนำให้ใช้วิธีการดึงข้อมูล (Target t) (ดูเหมือนว่าจะเป็นปัญหาของการอ้างอิงที่อ่อนแอ ... ) แต่ฟังก์ชันนี้ ไม่มีใน picasso รุ่นล่าสุด (2.3.2) ฉันมีเพียงวิธีการดึงข้อมูล () แต่ฉันไม่สามารถใช้ใน (Mytarget) ได้ในเวลาเดียวกัน

คุณช่วยอธิบายวิธีใช้ fetch () กับเป้าหมายที่กำหนดเองได้ไหม ขอบคุณ.

เอกสาร: http://square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--


1
อย่าลืมใช้ okhttp 2.0.0 ฉันพบปัญหาเดียวกันเมื่อใช้ Picasso 2.3.2 กับ Okhttp 1.6.0
hakim

github.com/square/okhttp afaik เป็นข้อบังคับหากคุณใช้ Picasso 2.3.2 เพื่อรวมไลบรารี okhttp (และ okio) คุณใช้ eclipse หรือ android studio?
hakim

ฉันใช้ IntelliJ ฉันเคยเห็นการพึ่งพาผู้เริ่มต้นของฉันฉันไม่เห็น okhttp ... Picasso ดูเหมือนจะทำงานได้หากไม่มีมัน
psv

@psv คุณใช้วิธีแก้ปัญหาด้านล่างด้วยเครื่องหมายอย่างไร
Mustafa Güven

คำตอบ:


248

ตามที่ระบุไว้โดยผู้ตอบแบบสอบถามคนอื่น ๆ (@lukas และ @mradzinski) Picasso เก็บข้อมูลอ้างอิงที่ไม่เหมาะสมไปยังTargetวัตถุเท่านั้น แม้ว่าคุณจะสามารถจัดเก็บข้อมูลอ้างอิงที่ชัดเจนTargetในชั้นเรียนของคุณได้ แต่ก็ยังอาจเป็นปัญหาได้หากการTargetอ้างอิงViewในลักษณะใด ๆ เนื่องจากคุณจะต้องเก็บข้อมูลอ้างอิงที่ชัดเจนViewเช่นกัน (ซึ่งเป็นหนึ่งในสิ่งที่ Picasso ช่วยให้คุณหลีกเลี่ยงอย่างชัดเจน)

หากคุณอยู่ในสถานการณ์นี้ขอแนะนำให้แท็กTargetไปที่View:

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

แนวทางนี้มีประโยชน์ในการให้ Picasso จัดการทุกอย่างแทนคุณ มันจะจัดการWeakReferenceวัตถุสำหรับแต่ละมุมมองของคุณ - ทันทีที่ไม่ต้องการอีกต่อไปสิ่งที่Targetประมวลผลภาพก็จะถูกปล่อยออกมาด้วยดังนั้นคุณจะไม่ติดอยู่กับหน่วยความจำรั่วเนื่องจากเป้าหมายที่มีอายุยาวนาน แต่เป้าหมายของคุณจะคงอยู่ ตราบเท่าที่มุมมองยังมีชีวิตอยู่


15
บันทึกวันของฉัน ขอบคุณ
cy198706

24
ฉันไม่มีมุมมองภาพจะแก้ปัญหานี้ได้อย่างไร เมื่อต้องรับมือกับสถานการณ์แบบนี้ gc คือศัตรูที่แย่กว่าของคุณ
tim687

3
คุณสามารถจัดเก็บไว้ใน ArrayList <เป้าหมาย> และจะใช้งานได้อย่าลืมล้างรายการอาร์เรย์นั้น :-)
Oliver Dixon

2
ใน onBitmapLoaded และ onBitmapFailed ฉันยังทำ imageView.setTag (null) หลังจากประมวลผลบิตแมป มันไม่จำเป็น?
Jaguar

1
ขอบคุณ! แค่ช่วยชีวิตฉัน :)
yusufiga

55

Picasso ไม่ได้มีการอ้างอิงที่ชัดเจนไปยังวัตถุเป้าหมายดังนั้นจึงถูกเก็บรวบรวมและ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

ในเอกสารระบุว่าคุณต้องลบล้างObject.equals(Object)และObject.hashCode()วิธีการ คุณมีตัวอย่างการทำงานหรือไม่?
ชิป

มันเขียนที่ไหน? ฉันยังคงมีปัญหาแม้จะอ้างอิงถึง Target () อย่างชัดเจน
psv

ตอนนี้ฉันได้ติดตั้ง okHttp แล้วมันเร็วขึ้นเล็กน้อยในการโหลด แต่ฉันยังคงมีปัญหาเดิมในการเปิดตัวครั้งแรก ความคิดใด ๆ ?
psv

@psv: คุณได้แก้ปัญหาการเปิดตัวครั้งแรกของ picasso หรือไม่? ผมมีปัญหาเดียวกัน? ถ้าคุณแก้แล้วคุณแก้อย่างไร?
TheDevMan

25

ถ้าฉันมี ImageView ฉันจะทำแบบนี้: imageView.setTag (เป้าหมาย);

ฉันใช้วิธีแก้ปัญหาถัดไปเพื่อโหลด Bitmaps ในการแจ้งเตือนดังนั้นฉันจึงต้องการเพียงบิตแมป

ดังนั้นสร้าง Set Witch จะเก็บวัตถุเป้าหมายและลบออกเมื่อโหลดเสร็จ

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 กล่าว (และการอ้างถึง) Picasso ไม่ได้มีการอ้างอิงที่ชัดเจนไปยังวัตถุเป้าหมาย เพื่อหลีกเลี่ยงการรวบรวมขยะคุณต้องมีการอ้างอิงที่ชัดเจนถึงวัตถุ

เกี่ยวกับวิธีการดึงข้อมูล () ค่อนข้างชัดเจนในเอกสารประกอบว่าไม่ให้ใช้ fetch () กับ ImageView หรือ Target เพียงแค่ "อุ่น" แคชและไม่มีอะไรอื่นดังนั้นคุณจะไม่สามารถใช้งานได้ในแบบที่คุณ ต้องการ.

ฉันขอแนะนำให้คุณใช้ข้อมูลอ้างอิงที่ชัดเจนเช่น @lukas อธิบายมันควรจะใช้งานได้ หากไม่ได้โปรดเปิดประเด็นใหม่ในหน้า GitHub ของโครงการ


3

ฉันพบปัญหาที่คล้ายกันและการอ้างอิงถึงเป้าหมายไม่ได้ช่วยเลยดังนั้นฉันจึงใช้รหัสต่อไปนี้ซึ่งส่งคืน Bitmap:


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!

ฉันจำเป็นต้องใช้ทั้งสองอย่างเนื่องจากจุดประสงค์ของโปรเจ็กต์ของฉันคือใช้ api การดาวน์โหลดรูปภาพ 2 รูปที่แตกต่างกันเพื่อแสดงแกลเลอรีรูปภาพและเพื่อให้ผู้ใช้สามารถเลือก API ที่จะใช้

ฉันต้องบอกว่าฉันรู้สึกทึ่งกับผลลัพธ์ api ของ Glide ทำงานได้อย่างไร้ที่ติในทุก ๆ ด้าน (เป้าหมายของ Glide ไม่มีการอ้างอิงที่อ่อนแอ) Picasso ที่ไร้เดียงสาทำให้ฉันรู้สึกแย่ (นั่นเป็นครั้งแรกที่ฉันใช้ Glide ฉันมักจะใช้ 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.