3

I use SimpleCursorAdapter and GridActivity (extended Activity written by me based on ListActivity) to load music albums from MediaStore, and use AsyncTask load each album art .

I tried this in bindView or getView, like this:

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

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

    }
}

But images shifting between gridview items randomly.

You can see screen record video here.

edited prevent this error by setTag() and getTag() is also no effect.

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

    }
}
mariotaku
  • 693
  • 1
  • 10
  • 26

1 Answers1

1

The Problem is, that the AsyncTask don't know für which ImageView they where started, respectivley they overlap.

To prevent this you need to do the following: In your getView Method (before calling the AsyncTask-Constructor you need so set a Tag to your ImageView: myImageView.setTag(object). The best choice is, if you use the object from which getView gets its information. In you case i think it is the ArrayList with the Album-Information. Let' say myImageView.setTag(myAlbumArray.get(position)) THE TAG MUST BE UNIQUE
Now add a new String 'tag' to your AsyncTask class and add this.tag = imageview.getTag().toString().
Now finally add the test in your onPostExecute:

 if (imageview.getTag().toString().equals(tag)) {
// you got the right imageView, *your PostExecute Code* }
else {// wrong one, do nothing
}
Thommy
  • 5,070
  • 2
  • 28
  • 51
  • I think my problem may not caused by this. – mariotaku Jan 16 '12 at 15:36
  • Well i got the same problem like shown in your video, and solved it with this code. – Thommy Jan 16 '12 at 15:44
  • `new AsyncAlbumArt(imageview, false)` sets the only imageview for this task to operate. You can see my code `org.musicmod.android.activity.AlbumBrowserActivity` – mariotaku Jan 16 '12 at 15:44
  • But in your onPost you set ImageView's source to the Bitmap retreived in AsyncTask. And there is the Problem, this ImageView ist not necessary the same which you give in the AsyncTasks constructor. That is a known problem. – Thommy Jan 16 '12 at 15:47
  • Sorry for the previous delayed reply. Thank you so much. I'll try it soon and give you feedback. – mariotaku Jan 16 '12 at 15:49
  • It don't work...I will post my getView method and modified code below. – mariotaku Jan 17 '12 at 09:18
  • Hm, don't see any error there. Maybe the error is in CachedArtowrk-method – Thommy Jan 17 '12 at 12:58
  • Well, now my only resolution is update image without using asynctask. If you are not busy you could view my all source code to find getCachedArtWork method. – mariotaku Jan 17 '12 at 13:28
  • 1
    I found the reason that image shifting is garbage collector. Same problem is also happened when others try to load image in another thread. – mariotaku Jan 17 '12 at 13:32
  • Could you tell, how you fix it? – neworld Feb 07 '13 at 15:40
  • So tell us what the reason was and how to fix it please. – HGPB Apr 19 '13 at 11:08