В приложении используется recyclerwiew для отображения списка контактов. В старой версии приложения один раз и на всю жизнь качались 300мб фотографий пользователей и потом в OnBindViewHolder просто доставались из базы данных. Никаких проблем в отображении (в recyclerview) не возникало.
Сейчас же фотографии скачиваются из сети по мере необходимости их отображения (естественно асинхронно), записываются в БД и результат отображается в нужном айтеме. Всё выглядит прекрасно, но как только происходит scroll списка контактов, их фотографии дублируются и только когда scroll остановится, они исчезают, пересоздаются уже корректно отображаются. То есть recyclerview в момент остановки мигает как новогодняя ёлка.
Понятно, что это происходит от того, что recyclerview переиспользует видимые itemview. Проблема решается, если перейти с recyclerview на listview и обязательно установить ему setHasFixedSize(true). Однако, мне просто необходимо использовать recyclerview, а не listview.
Код адаптера:
@Override
public void onBindViewHolderCursor(ContactViewHolder holder, Cursor cursor) {
String firstName = cursor.getString(cursor.getColumnIndex(DatabaseSchemas.Profile.FIRST_NAME));
String lastName = cursor.getString(cursor.getColumnIndex(DatabaseSchemas.Profile.LAST_NAME));
holder.mName.setText(String.format("%s %s", lastName, firstName));
long profileId = cursor.getInt(cursor.getColumnIndex(DatabaseSchemas.Profile.ID));
boolean gender = cursor.getString(cursor.getColumnIndex(DatabaseSchemas.Profile.SEX)).equals("M");
holder.mPhoto.setEmploeePhoto(mContext, profileId, gender, holder.mPhoto);
//ВНИМАНИЕ ниже старый метод отображения изображений, который работает без проблем
//ImageUtils.displayUserPhoto(mContext, profileId, gender, holder.mPhoto);
holder.setHighlightQuery(mQuery);
}
Теперь подробно о новом методе holder.mPhoto.setEmploeePhoto, который как раз либо показывает изображение из базы данных, либо качает из сети, сохраняет в БД и показывает.
public void setEmploeePhoto(final Context context, final long mEmployee_id, final boolean gender, final ImageView imageView) {
if (ImageUtils.userPhotoIsExist(context, mEmployee_id)){
ImageUtils.displayUserPhoto(context, mEmployee_id, gender, imageView);
//ВНИМАНИЕ, это тот самый метод отображения фото,
//который был закомментирован в OnBindViewHolder,
//и ещё ниже он снова используется уже после окончания загрузки и записи в БД.
//Но только пока он работал в OnBindViewHolder, фото прекрасно отображались при скроллинге,
//а вот здесь появляется проблема с дублированием и перемигиванием новогодней ёлкой
}
else {
JSONObject filter = new JSONObject();
JSONArray values = new JSONArray();
values.put(String.valueOf(mEmployee_id));
try {
filter.put("values", values);
filter.put("field", "user_id");
} catch (JSONException e) {
e.printStackTrace();
return;
}
new SapApi(getContext()).getPhoto(filter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<InputStream>() {
@Override
public void call(final InputStream inputStream) {
//Если фото успешно скачалось из сети
new LoadAndWritePhoto(context,mEmployee_id, gender, imageView, inputStream).execute();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Toast.makeText(getContext(), throwable.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
public class LoadAndWritePhoto extends AsyncTask<Void, Void, Void> {//Потому что нельзя записывать данные в БД в главном потоке
Context mmContext;
long profileId;
boolean gender;
ImageView mImageView;
InputStream inputStream;
public LoadAndWritePhoto(Context mmContext, long profileId, boolean gender, ImageView mImageView, InputStream inputStream) {
this.mmContext = mmContext;
this.profileId = profileId;
this.gender = gender;
this.mImageView = mImageView;
this.inputStream = inputStream;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {//фоновая логика
{
try {
PhotosSdCardWriter.writePhotosFromJson(mmContext, inputStream);
} catch (Exception e){
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {//обновление интерфейса до окончания выполнения потока (не требуется)
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Void aVoid) {//результат фоновой логики
super.onPostExecute(aVoid);
try {
ImageUtils.displayUserPhoto(mmContext, profileId, gender, mImageView);
}catch (Exception e){
e.printStackTrace();
}
}
}