Android: Sichtbare ListView-Bilder flackern, wenn Daten zu ArrayAdapter hinzugefügt werden

Ich habe einen benutzerdefinierten Adapter, der ArrayAdapter erweitert. Er implementiert die Muster der Ansichtshalter, um Daten (Text + Bild) von einem Webdienst anzuzeigen.

Zum faulen Laden der Bilder verwende ich das Async-Tasks-Muster aus dem Advanced Training auf der Entwicklerseite von Android.

Ich benutze auch Disk + RAM-Bitmap-Cache.

Wenn zusätzliche Daten abgerufen werden müssen, füge ich eine Fußzeilenansicht hinzu, die durch Anklicken zusätzliche Daten vom Webdienst abruft und dem Adapter hinzufügt.

Das Problem ist, dass sich beim Hinzufügen dieser neuen Daten einige der sichtbaren Bilder ändern und sofort wieder zurückkehren, was zu einem seltsamen Flackern führt.

Ansonsten funktioniert alles einwandfrei und das Scrollen ist reibungslos.

Soweit ich weiß, treten diese Bildänderungen auf, wenn die sichtbaren Ansichten aktualisiert werden, wenn neue Daten hinzugefügt werden.

Gibt es eine Möglichkeit, dieses unerwünschte Verhalten zu umgehen?

Dies ist die Klasse, die die asynchronen Aufgaben herunterlädt und verwaltet

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;
}

}

Dies ist der Adapter:

private class PlaceAdapter erweitert 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 ist einWeakHashMap<ImageView, String> das liegt zwischen einemImageView und eine URL, so dass redundante asynchrone Aufgabenaufrufe reduziert werden können, indem geprüft wird, ob dieImageView zeigt bereits das gewünschte Bild. Ohne diese Implementierung tritt bei Datenänderungen in allen sichtbaren Bildern ein Flackern auf. dabei kommt es nur bei einigen bildern vor.

BEARBEITEN: Ich habe versucht, mögliche Ursachen für dieses Problem zu beseitigen. Zuerst habe ich versucht, die Cache-Implementierung vollständig zu umgehen und jede Bitmap aus dem Netzwerk herunterzuladen. Dann habe ich versucht, meinen Adapter mit dem CommonsWare Endless-Adapter zu verpacken, und mit beiden habe ich das gleiche Ergebnis erzielt Dadurch bleiben nur die ImageDownloader-Klasse und mein Adapter als mögliche Ursachen. Ich bin völlig verloren.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage