Sử dụng Picasso để nhận cuộc gọi lại bằng Bitmap


83

Tôi đang sử dụng Picasso để tải xuống hình ảnh cho ứng dụng của mình.

Tôi đang ở trong một tình huống mà tôi cần phải truy cập Bitmapđầu tiên trước khi nó được tải vào ImageView. Sự hiện diện của Downloader.Responselớp dường như cho thấy điều này là có thể, nhưng tôi không thể tìm thấy bất kỳ ví dụ sử dụng nào. Tôi không muốn viết thêm nhiều mã để xử lý không đồng bộ một trường hợp cụ thể này nếu có thể xảy ra với Picasso.

Bất cứ ai có thể chỉ cho tôi làm thế nào để làm điều đó?


Câu trả lời:


172

Tìm thấy câu trả lời trên github trong trường hợp bất kỳ ai đang thắc mắc:

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

Bài đăng khuyến nghị không sử dụng một cuộc gọi lại ẩn danh và thay vào đó sử dụng một biến phiên bản cho mục tiêu.


30
Tốt nhất là bạn nên triển khai Targettrực tiếp trên một chế độ xem hoặc đối tượng chủ sở hữu chế độ xem. Nếu bạn không làm điều này, bạn cần phải duy trì một tham chiếu mạnh mẽ đến cá thể ở đâu đó nếu không nó sẽ bị thu thập rác.
Jake Wharton

@JakeWharton: nếu tôi muốn áp dụng hoạt ảnh tùy chỉnh trên mọi mục của a ListView, bạn đề xuất làm điều gì đó như private static ViewHolder { private ImageView imageView; private Target target = new Target() { public void onBitmapLoaded() { // do animation on imageView } } }:?
mbmc

@JakeWharton giải thích nó ở đây github.com/square/picasso/issues/308 trong nhận xét cuối cùng.
toobsco42

8
onBitmapLoaded không ghé cảng tại lần đầu tiên sau onPrepareLoad
Amit Thaper

Cảm ơn vì ví dụ. Tôi chỉ thiếu một cuộc gọi siêu khủng trong onDestroy.
Ben Groot

68

lấy từ đây :

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

Cập nhật (04/05/2016):

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

                    }
                });

Cập nhật (22/11/2016)

hoặc sử dụng một tham chiếu mạnh Targetđể nó không bị thu gom

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

Kotlin

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

                  }
                }

6
nặc danh Mục tiêu có thể được thu thập rác
Steve M

@SteveM Và điều đó sẽ làm gì? Hủy yêu cầu? Ngăn chặn bitmap được tải?
nurettin

@nurettin Tôi giả sử Picasso (hoặc Glide) có một số loại tham chiếu yếu đến mục tiêu. Vì vậy, nếu nó ẩn danh thì không có tham chiếu khó và nó dễ bị GC. Khi Picasso kiểm tra tham chiếu, nó sẽ không có giá trị nên lệnh gọi lại sẽ không được gọi.
Steve M

Vì vậy, giải pháp này thực sự không tốt vì đôi khi GC có thể chạy giữa quá trình tải và gọi lệnh gọi lại và khiến lệnh gọi lại không được gọi.
Steve M

@SteveM Tôi lưu trữ một ứng dụng trên google play tải một loạt các biểu tượng trong khi cuộn lượt xem danh sách của nó với ít nhất 2000 người dùng tại bất kỳ trường hợp nào, mở rộng một số biểu tượng bằng phương pháp này, nhưng tôi không thấy bất kỳ phàn nàn nào, nhận xét ( Tôi nhận được rất nhiều) hoặc báo cáo sự cố về các biểu tượng không tải. Vì vậy, ít nhất theo giai thoại, nó không được thu gom rác vì một số lý do.
nurettin

7

Điều gì có thể dễ dàng hơn tiếp theo:

val url: String = "https://...."
val bitmap: Bitmap = Picasso.with(context).load(url).get()

Nên được gọi từ không phải chủ đề chính!

hoặc với 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)
    }
}

Truy xuất Bitmap:

getBitmapSingle(Picasso.with(context), "https:/...")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ bitmap ->
                // val drawable = BitmapDrawable(context, bitmap)
                }, Throwable::printStackTrace)

Tôi đã sử dụng Picasso v.2.5.2


2

Tôi nghĩ có thể một số bạn sẽ thích phiên bản RxJava của câu trả lời ở trên ... Đây là:

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

PS Khi đăng ký, hãy lưu trữ tham chiếu đăng ký về hoạt động của bạn, nếu không, mục tiêu sẽ được GC trước khi bạn nhận được phản hồi ...


Có vẻ như mã này hiện không hoạt động với RxAndroid mới nhất
Pavandroid
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.