Я думаю, что проблема в том, что указано Eselfar.Когда вы запрашиваете URI для firebase, это должно быть сделано в асинхронном потоке.Это означает, что в то время как URL итерации n получен, адаптер продолжает выполнять итерации в вашем списке.
Эти 2 потока выполняются одновременно, поэтому переменная владельца постоянно переназначается, вероятно, до тех пор, пока итерация не достигнет своего последнего видимого элемента(просмотр).
Это приводит к такому сценарию:
for each view {
request image url (for example 2 seconds)
assign holder variable (for example 0.0002 seconds)
}
в то время, как извлекается первый URL-адрес изображения (2 секунды), адаптер завершил итерацию.Таким образом, переменная-держатель теперь имеет то же значение, которое является последним значением всей итерации.Через 2 секунды для первого URL-адреса изображения (и т. Д. Для оставшегося URL-адреса изображения) он входит в метод OnSuccessListener.onSuccess
, для него устанавливается Glide изображение в переменную holder.profile_pic
.Но эта переменная, как было сказано ранее, теперь принадлежит к последней выполненной итерации.
Итак, ваша проблема в том, что вы смешиваете синхронизацию и асинхронный подход.
Возможное решение - сначала получить все изображенияURL, затем удалите эту асинхронную задачу (storageReference.getDownloadUrl()
) и сделайте все вещи в одном UIThread.
Я думаю, что самое простое решение (но, вероятно, не самое лучшее) - это создать собственный OnSuccessListener и собственный OnFailureListenerнапример:
public class MySuccessListener extends OnSuccessListener {
Holder holder;
public MySuccessListener(Holder holder) {
this.holder = holder;
super();
}
@Override
public void onSuccess(Uri uri) {
Glide.with(context).load(uri).apply(RequestOptions.circleCropTransform()).into(holder.profile_pic);
}
}
public class MyFailureListener extends OnFailureListener {
Holder holder;
public MyFailureListener(Holder holder) {
this.holder = holder;
super();
}
@Override
public void onFailure(@NonNull Exception exception)
int errorCode = ((StorageException) exception).getErrorCode();
if (errorCode == StorageException.ERROR_OBJECT_NOT_FOUND) {
Picasso.get()
.load(R.drawable.user)
.resize(70,70)
.into(holder.profile_pic);
}
}
}
Обратите внимание, что вы передаете текущий держатель в конструкторы слушателей, поэтому, когда асинхронная задача заканчивается, вы можете выбрать правильный держатель.Затем вы можете обновить свой код следующим образом:
storageReference.getDownloadUrl().addOnSuccessListener(new MyFailureListener<Uri>(holder))
.addOnFailureListener(new MyFailureListener(holder));
Теперь я не могу его протестировать, и в IDE мой код может быть неточным, но в основном вы должны понимать предложенный способ.
Обратите внимание, чтоВы используете Пикассо и Glide.Эти две библиотеки делают одно и то же, я предлагаю вам использовать одну из них и удалить ненужную зависимость.