Пикассо изображения загрузки и кэширование поведения
Поэтому недавно я хотел опробовать функцию кэширования в библиотеке Пикассо, и я попал в эту запутанную ситуацию:
Я получаю имена и пути к файлам изображений с моего веб-сервера (используя Retrofit2) и сохраняю их в ImageComponent
объекты (модель):
public class ImageComponent {
private int id; // 'id' in database
private String filename; // image name
private String path; // image path in server storage
private Bitmap bitmap;
// Overloaded constructor
// Getters & setters
}
Теперь, когда загрузка прошла успешно, я заполняю RecyclerView
с этими изображениями, используя Пикассо. Процесс загрузки и накачки успешен, но при кэшировании изображений он становится немного сложным.
Случай 1: использование android.util.LruCache
(Для удобства выложу весь код Recyclerview
Адаптер. Постараюсь быть лаконичным)
// imports
import android.util.LruCache;
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> {
private Context mContext; // Activity's context
private List<ImageComponent> mImages; // The imageComponents to display
// The contreversial, infamous cache
private LruCache<Integer, Bitmap> mImageCache;
public ImageAdapter(Context context, List<ImageComponent> images) {
mContext = context;
mImages = images;
// Provide 1/8 of available memory to the cache
final int maxMemory = (int)(Runtime.getRuntime().maxMemory() /1024);
final int cacheSize = maxMemory / 8;
mImageCache = new LruCache<>(cacheSize);
}
@Override
public ImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Nothing special
}
@Override
public void onBindViewHolder(final ImageAdapter.ViewHolder holder, final int position) {
// Current ImageComponent
ImageComponent imageComponent = mImages.get(position);
// Full image path in server storage
String imagePath = Constants.SERVER_IP_ADDRESS + Constants.UPLOADS_DIRECTORY
+ imageComponent.getPath();
// Display the file's name
holder.text.setText(imageComponent.getFilename());
final ImageView imageView = holder.image;
// Get bitmap from cache, check if it exists or not
Bitmap bitmap = mImageCache.get(imageComponent.getId());
if (bitmap != null) {
Log.i("ADAPTER", "BITMAP IS NOT NULL - ID = " + imageComponent.getId());
// Image does exist in cache
holder.image.setImageBitmap(imageComponent.getBitmap());
}
else {
Log.i("ADAPTER", "BITMAP IS NULL");
// Callback to retrieve image, cache it & display it
final Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
ImageComponent img = mImages.get(position);
// Display image
holder.image.setImageBitmap(bitmap);
// Cache the image
img.setBitmap(bitmap);
mImages.set(position, img);
mImageCache.put(img.getId(), bitmap);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
// Tag the target to the view, to keep a strong reference to it
imageView.setTag(target);
// Magic
Picasso.with(mContext)
.load(imagePath)
.into(target);
}
}
@Override
public int getItemCount() {
return mImages.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView text;
// Constructor & view binding, not that special
}
}
result1
(Обратите внимание на эти 2 последних изображения и то, как они показывают другие предыдущие изображения перед отображением правильного)
Несколько заметок:
- Я столкнулся с проблемой, когда изображения вообще не отображались. После некоторого исследования я нашел этот ответ, который предложил связать
target
кImageView
, (работал) - Я не совсем понял, как Пикассо кэширует изображения. Это автоматический или ручной процесс? В этом ответе говорится, что Пикассо выполняет эту задачу для вас. Но когда я действительно попробовал (без андроида Lrucache), кеширование, похоже, не выполнялось: изображения перезагружались каждый раз, когда я прокручивал назад и вперед.
- На самом деле я собирался опубликовать второй вариант использования, когда все пошло еще хуже, используя Пикассо
Lrucache
(изображения показывались случайным образом, и меняются с каждым свитком), но я думаю, что этот пост уже достаточно длинный.
Мои вопросы:
- Почему я получаю это странное поведение? (как показано в прикрепленном GIF)
- Как работает весь этот процесс кэширования? Должен ли я (или мог ли я) использовать Lrucache при использовании Пикассо?
- Какая разница между
Lrucache
что идет с SDK & Picasso? (Производительность, лучшие сценарии использования и т. Д.)
1 ответ
Я думаю, что использование кеша LRU и Picasso вызывает странное поведение. Я использовал Picasso для кэширования изображения в адаптер, который работает совершенно нормально. Вы можете проверить здесь
Кэша Picasso Изображение автоматически при использовании с адаптером, оно будет кэшироваться следующим образом, если дочерний элемент представления списка /Recycler не виден, он прекратит кэширование изображения для соответствующего дочернего элемента. Поэтому лучше использовать Picasso отдельно с Adapter.
Основное использование Picasso поверх LRU кеша в том, что Picasso прост в использовании. пример: указание размера кэша памяти в Picasso.
Picasso picasso = new Picasso.Builder(context) .memoryCache(new LruCache(250)) .build();
Picasso также позволяет уведомлять пользователя с помощью Image при возникновении ошибки при загрузке - держателя по умолчанию для Imageview перед загрузкой полного изображения.
Надеюсь, поможет.