GridView + CursorAdapter + AsyncTask загружает изображение в произвольном порядке - PullRequest
3 голосов
/ 16 января 2012

Я использую SimpleCursorAdapter и GridActivity (расширенная активность, написанная мной на основе ListActivity) для загрузки музыкальных альбомов из MediaStore и использую AsyncTask load каждый обложка альбома.

Я пробовал это в bindView или getView, вот так:

new AsyncAlbumArtLoader(viewholder.album_art, mShowFadeAnimation).execute(aid, width, height);

класс AsyncAlbumArtLoader:

private class AsyncAlbumArtLoader extends AsyncTask<Object, Void, Bitmap> {

    boolean enable_animation = false;
    private ImageView imageview;

    public AsyncAlbumArtLoader(ImageView imageview, Boolean animation) {

        enable_animation = animation;
        this.imageview = imageview;
    }

    @Override
    protected void onPreExecute() {

        if (enable_animation) {
            imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
                    android.R.anim.fade_out));
            imageview.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    protected Bitmap doInBackground(Object... params) {

        return MusicUtils.getCachedArtwork(getApplicationContext(), (Long) params[0],
                (Integer) params[1], (Integer) params[2]);
    }

    @Override
    protected void onPostExecute(Bitmap result) {

        if (result != null) {
            imageview.setImageBitmap(result);
        } else {
            imageview.setImageResource(R.drawable.albumart_mp_unknown_list);
        }
        if (enable_animation) {
            imageview.setVisibility(View.VISIBLE);
            imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
                    android.R.anim.fade_in));
        }

    }
}

Но изображения смещаются между элементами сетки в случайном порядке.

Вы можете посмотреть видео с экрана записи здесь .

отредактировано предотвратить эту ошибку с помощью setTag () и getTag () также не действует.

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = super.getView(position, convertView, parent);

        mAlbumCursor.moveToPosition(position);

        ViewHolder viewholder = (ViewHolder) view.getTag();

        String album_name = mAlbumCursor.getString(mAlbumIndex);
        if (album_name == null || MediaStore.UNKNOWN_STRING.equals(album_name)) {
            viewholder.album_name.setText(R.string.unknown_album_name);
        } else {
            viewholder.album_name.setText(album_name);
        }

        String artist_name = mAlbumCursor.getString(mArtistIndex);
        if (album_name == null || MediaStore.UNKNOWN_STRING.equals(album_name)) {
            viewholder.artist_name.setText(R.string.unknown_artist_name);
        } else {
            viewholder.artist_name.setText(artist_name);
        }

        // We don't actually need the path to the thumbnail file,
        // we just use it to see if there is album art or not
        long aid = mAlbumCursor.getLong(mAlbumIdIndex);
        int width = getResources().getDimensionPixelSize(R.dimen.gridview_bitmap_width);
        int height = getResources().getDimensionPixelSize(R.dimen.gridview_bitmap_height);

        viewholder.album_art.setTag(aid);
        new AsyncAlbumArtLoader(viewholder.album_art, mShowFadeAnimation, aid, width, height).execute();

        long currentalbumid = MusicUtils.getCurrentAlbumId();
        if (currentalbumid == aid) {
            viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0,
                    R.drawable.ic_indicator_nowplaying_small, 0);
        } else {
            viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
        }

        return view;
    }


// FIXME image loaded some times incorrect
private class AsyncAlbumArtLoader extends AsyncTask<Object, Void, Bitmap> {

    boolean enable_animation = false;
    private ImageView imageview;
    private long album_id;
    private int width,height;

    public AsyncAlbumArtLoader(ImageView imageview, Boolean animation, long album_id, int width, int height) {

        enable_animation = animation;
        this.imageview = imageview;
        this.album_id = album_id;
        this.width = width;
        this.height = height;
    }

    @Override
    protected void onPreExecute() {

        if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
            return;
        }

        if (enable_animation) {
            imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
                    android.R.anim.fade_out));
            imageview.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    protected Bitmap doInBackground(Object... params) {

        if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
            return null;
        }

        return MusicUtils.getCachedArtwork(getApplicationContext(), album_id,
                width, height);
    }

    @Override
    protected void onPostExecute(Bitmap result) {

        if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
            return;
        }

        if (result != null) {
            imageview.setImageBitmap(result);
        } else {
            imageview.setImageResource(R.drawable.albumart_mp_unknown_list);
        }
        if (enable_animation) {
            imageview.setVisibility(View.VISIBLE);
            imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
                    android.R.anim.fade_in));
        }

    }
}

1 Ответ

1 голос
/ 16 января 2012

Проблема в том, что AsyncTask не знает, какой ImageView они где начали, соответственно перекрывают.

Чтобы предотвратить это, вам нужно сделать следующее: В вашем getView методе (перед вызовомAsyncTask-Constructor вам нужно, поэтому установите тег для вашего ImageView: myImageView.setTag(object). Лучший выбор, если вы используете объект, из которого getView получает информацию. В вашем случае я думаю, что это ArrayList с информацией об альбоме.Давайте скажем myImageView.setTag(myAlbumArray.get(position)) ТЕГ ДОЛЖЕН БЫТЬ УНИКАЛЬНЫМ
Теперь добавьте новый строковый тег в ваш класс AsyncTask и добавьте this.tag = imageview.getTag().toString().
Теперь, наконец, добавьте тест в ваш onPostExecute:

 if (imageview.getTag().toString().equals(tag)) {
// you got the right imageView, *your PostExecute Code* }
else {// wrong one, do nothing
}
...