Android: widoczne obrazy ListView migają podczas dodawania danych do ArrayAdapter

Mam niestandardowy adapter, który rozszerza ArrayAdapter, implementuje wzorce uchwytów widoku, aby wyświetlać dane (tekst + obraz) z usługi internetowej.

dla leniwego ładowania obrazów Używam wzorca zadań asynchronicznych z zaawansowanego szkolenia na stronie programistów Androida,

Używam także pamięci podręcznej bitmapy dysku + ram.

gdy istnieją dodatkowe dane do pobrania, dodajemy widok stopki, który po kliknięciu powoduje pobranie dodatkowych danych z usługi internetowej i dodanie jej do adaptera.

Problem polega na tym, że kiedy te nowe dane są dodawane, niektóre widoczne obrazy zmieniają się i natychmiast się zmieniają, co powoduje dziwne migotanie.

poza tym wszystko działa dobrze i przewijanie jest płynne.

O ile rozumiem, zmiany obrazu mają miejsce, gdy widoczne widoki są odświeżane po dodaniu nowych danych.

czy istnieje sposób na ominięcie tego niechcianego zachowania?

jest to klasa pobierająca i zarządzająca zadaniami asynchronicznymi

public class ImageDownloader {
private ImageCache mCache;
private int reqWidth;
private int reqHeight;

public void download(String url, ImageView imageView, ImageCache imageCache, int reqHeight, int reqWidth) {
    mCache = imageCache;
    this.reqHeight = reqHeight;
    this.reqWidth = reqWidth;

    if (cancelPotentialDownload(url, imageView)) {
        BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);

        DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
        imageView.setImageDrawable(downloadedDrawable);
        task.execute(url);
    }
}

private class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;
    private WeakReference<ImageView> imageViewReference;

    public BitmapDownloaderTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    @Override
    protected Bitmap doInBackground(String... strings) {
        Bitmap bitmap = null;
        try {
            bitmap =  mCache.getBitmapFromURL(strings[0], reqWidth, reqHeight);
        } catch (IOException e) {
        }

        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) bitmap = null;

        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

private static class DownloadedDrawable extends ColorDrawable {
    private WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

    public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
        bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
        return bitmapDownloaderTaskReference.get();
    }
}

private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
    if (imageView != null) {
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof DownloadedDrawable) {
            DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
            return downloadedDrawable.getBitmapDownloaderTask();
        }
    }
    return null;
}

private static boolean cancelPotentialDownload(String url, ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

    if (bitmapDownloaderTask != null) {
        String bitmapUrl = bitmapDownloaderTask.url;
        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
            bitmapDownloaderTask.cancel(true);
        } else {
            return false;
        }
    }
    return true;
}

}

to jest adapter:

klasa prywatna PlaceAdapter extends ArrayAdapter {final int viewResourceId;

    public PlaceAdapter(Context context, int textViewResourceId, List<PlaceModel> objects) {
        super(context, textViewResourceId, objects);
        viewResourceId = textViewResourceId;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            convertView = inflater.inflate(viewResourceId, null);

            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        PlaceModel place = getItem(position);

        holder.name.setText(place.getName());
        holder.address.setText(place.getVicinity());
        holder.position = position;

        if (place.getIcon() != null) {
            String url = mImageViewUrls.get(holder.image);
            if (url == null || (url != null && !url.equals(place.getIcon()))) {
                mDownloader.download(place.getIcon(), holder.image, mCache, 100, 100);
                mImageViewUrls.put(holder.image, place.getIcon());
            }
        } else {
            holder.image.setImageBitmap(null);
            mImageViewUrls.remove(holder.image);
        }

        return convertView;
    }
}

private class ViewHolder {
    public final ImageView image;
    public final TextView name;
    public final TextView address;
    public int position;

    public ViewHolder(View row) {
        image = (ImageView) row.findViewById(R.id.placeRow_imageView);
        name = (TextView) row.findViewById(R.id.placeRow_placeName);
        address = (TextView) row.findViewById(R.id.placeRow_placeAddress);
    }
}

mImageViewUrls jestWeakHashMap<ImageView, String> to mapuje międzyImageView i adres URL, więc wywołania nadmiarowych zadań asynchronicznych można zmniejszyć, sprawdzając, czyImageView już pokazuje wymagany obraz. bez tej implementacji migotanie pojawia się na wszystkich widocznych obrazach podczas zmiany danych. dzięki temu zdarza się tylko z niektórymi obrazami.

EDYCJA: Próbowałem wyeliminować możliwe przyczyny tego problemu, najpierw próbowałem całkowicie ominąć implementację pamięci podręcznej i pobrać każdą bitmapę z sieci, a następnie próbowałem zawinąć mój adapter za pomocą adaptera Endless Commons Commons i uzyskać ten sam wynik .. więc pozostawia to tylko klasę ImageDownloader i mój adapter jako możliwe przyczyny.

questionAnswers(4)

yourAnswerToTheQuestion