onBitmapLoaded of Target об'єкт не викликається при першому завантаженні


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/isissue/39, яка рекомендує використовувати метод fetch (Target t) (здається, це проблема слабкого посилання ...), але ця функція недоступний в останньому випуску пікассо (2.3.2). У мене лише метод fetch (), але я не можу одночасно використовувати (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). Ви використовуєте затемнення або студію Android?
хакім

Я використовую IntelliJ. Я бачив мої залежності від граду, я не бачив 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);

Такий підхід має перевагу дозволити Picasso впоратись із вами за все. Він керуватиме WeakReferenceоб’єктами для кожного вашого перегляду - як тільки один більше не потрібен, будь-яка Targetобробка зображення також буде випущена, тому ви не застряжете у витоку пам'яті через довговічні цілі, але ваша ціль триватиме до тих пір, поки його погляд живий.


15
Врятував мій день. Дякую.
cy198706

24
У мене немає перегляду зображень, як потім вирішити цю проблему? У роботі з подібними ситуаціями, gc - ваш найгірший ворог
tim687

3
Ви навіть можете зберігати його в ArrayList <Target>, і він спрацює, просто пам’ятайте, щоб очистити цього arraylist :-)
Олівер Діксон,

2
У програмах onBitmapLoaded і onBitmapFailed я також роблю imageView.setTag (null) після обробки растрової карти. Це не потрібно?
Ягуар

1
Дякую! Щойно врятували мені життя :)
yusufiga

55

Пікассо не має чіткого посилання на об'єкт Target, тому його збирають сміття і 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 (target);

Я використовую наступне рішення для завантаження растрових зображень у сповіщення, тому мені потрібна лише растрова карта.

Таким чином, створити 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'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);
}

3

Як сказав @lukas (і цитуючи), Пікассо не має чіткого посилання на об'єкт Target. Щоб уникнути збирання сміття, ви повинні чітко посилатися на об'єкт.

Про метод fetch () У документації досить зрозуміло, що fetch () використовувати не з ImageView, а не з цільовим, це просто "розігріти" кеш і більше нічого, тому ви не зможете використовувати його так, як ви хочу.

Я рекомендую вам мати чітке посилання, як пояснив @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);
            }
        }
    }
});

Ще одна річ, яка працює набагато краще - це просто використання Glide!

Мені потрібно було використовувати обидва з них, оскільки метою мого проекту було використання двох різних зображень для завантаження зображень, щоб показати галерею зображень та дати користувачеві можливість вибрати, які саме api використовувати.

Треба сказати, я був вражений результатами, апі Гліде працював бездоганно у кожному аспекті (ціль Glide не має слабких орієнтирів) підлість Пікассо дала мені пекло (це був мій перший раз використання Glide, я зазвичай використовував Пікассо досі, здається, що сьогодні це зміниться ^^).


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'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.