OnBitmapLoaded объекта Target, не вызванного первой загрузкой
В моей функции:
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(), но я не могу использовать в (mytarget) в то же время
Не могли бы вы объяснить мне, как использовать fetch() с пользовательским Target, пожалуйста? Спасибо.
Doc: http://square.github.io/picasso/javadoc/com/squareup/picasso/RequestCreator.html#fetch--
Ответы
Ответ 1
Как отмечают другие респонденты (@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
обработки изображения также будет выпущена, так что вы не застряли в утечке памяти из-за долгоживущих целей, но ваша цель будет продолжаться до тех пор, пока ее представление будет живым.
Ответ 2
Picasso не содержит ссылки на объект Target, поэтому он собирает мусор, а onBitmapLoaded не вызывается.
Решение тихое, juste сильно ссылается на 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);
}
}
Ответ 3
Если бы у меня был ImageView, я бы просто сделал так: imageView.setTag(target);
Я использую следующее решение для загрузки Bitmaps в уведомления, поэтому мне нужно только растровое изображение.
Итак, создайте Set, который будет хранить объекты 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) {
}
}
Ответ 4
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() {
}
});
Ответ 5
Как и @lukas (и цитирует), Пикассо не содержит ссылки на объект Target. Чтобы избежать сбора мусора, вы должны держать ссылку на объект.
О методе fetch(). В документации довольно ясно, что fetch() не используется с ImageView или Target, это просто "нагревает" кеш и ничего больше, поэтому вы не сможете использовать его так, как вы хотите.
Я рекомендую вам иметь сильную ссылку, как объяснил @lukas, она должна работать. Если нет, пожалуйста, откройте новую проблему на странице GitHub проекта.
Ответ 6
Я столкнулся с подобной проблемой, и ссылка на цель не помогла, поэтому я использовал следующий код, который возвращает битмап:
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!
Мне нужно было использовать их оба, так как цель моего проекта состояла в том, чтобы использовать 2 разных файла загрузки изображений api, чтобы показать галерею изображений и дать пользователю возможность выбирать, какой api использовать.
Я должен сказать, что я был поражен результатами, Glide api работал безупречно во всех аспектах (цель Glide не имеет слабой ссылки). Удивительный Пикассо дал мне ад (это был мой первый раз с использованием Glide, я обычно использовал Picasso до сих пор кажется, что сегодня он изменится ^^).