본문 바로가기

PROGRAMING/Android

listView 항목에 Audio Albumart(thumbnail)을 지연 없이 나타내기.AsyncTask

ListView에 아래 그림과 같이 AlbumArt(thumbnail)을 표시하는데 

빠른 스크롤시에도 지연 현상이 없도록 AsyncTask를 이용한다.


최초 반응성이 많이 늦어지만 AsyncTask를 사용하므로써 1차적으로 많이 개선되었다.

(참고 자료 :http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/)


Source


class ViewHolder {

public long albumId;

public TextView tvTitle;

public TextView tvArtist;

public TextView tvDuration;

public ImageView ivAlbumArt;

}

ViewHolder에 albumArt를 구분할수 있는 albumId 필드를 추가한다.



long albumId = cursor.getLong(cursor

.getColumnIndex(android.provider.MediaStore.Audio.Media.ALBUM_ID));


holder.albumId = albumId;

new ThumbnailTask(albumId, holder).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, getActivity());



CursorAdapter의 bindView 구문에서 albumId 값을 가져와 AsyncTask를 상속받아서 구현한

ThumbnailTask 객체의 생성자로 넘겨준다.


*중요 executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, getActivity());

첫번째 인자 AsyncTask.SERIAL_EXECUTOR해당 ThumbnailTask가 싱글 Thread로 동작함을 의미한다.

AsyncTask.THREAD_POOL_EXECUTOR로 바꿔주면 병렬 Thread로 동작하나 오류가 빈번하게 발생된다. 병렬 Thread로 구현을 하려면 더 많은 것을 고려해야한다. 그래서 이부분에서는 생략한다.


싱글 Thread도 실사용엔 크게 문제가 없을 만큼 동작된다.[단 빠른 Scroll시 지연현상이 조금 발생된다.)


class ThumbnailTask extends AsyncTask<Context, Integer, Bitmap> {

private long mAlbumId;

private ViewHolder mHolder;


public ThumbnailTask(long albumId, ViewHolder holder) {

mAlbumId = albumId;

mHolder = holder;

}


@Override

protected Bitmap doInBackground(Context... params) {

Bitmap bitmap = null;

if (mHolder.albumId == mAlbumId) {

Uri sArtworkUri = Uri

.parse("content://media/external/audio/albumart");

Uri sAlbumArtUri = ContentUris.withAppendedId(sArtworkUri, mAlbumId);

try {

ParcelFileDescriptor fd = params[0].getContentResolver()

.openFileDescriptor(sAlbumArtUri, "r");

bitmap = BitmapFactory.decodeFileDescriptor(

fd.getFileDescriptor(), null, null);

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} else {

this.cancel(isCancelled());

}

return bitmap;

}


@Override

protected void onPostExecute(Bitmap bitmap) {

if (mHolder.albumId == mAlbumId) {

if(null!=bitmap){

mHolder.ivAlbumArt.setImageBitmap(bitmap);

}

} else {

this.cancel(isCancelled());

}

}

}

생성자에서 넘겨받은 albumId와 ViewHolder개체를 사용하여 ViewHolder의 albumId와 같은 경우만

현재 화면에 나타나고 있다고 판단하여 bitmap을 ImageView 넣어주는 작업을 한다.

Scroll 시 ViewHolder 객체는 재 사용되기 때문에 ThumbnailTask 개체 albumId값은 화면에 표시되어야 하는 albumId로  바뀐다. 그러므로 생성자에서 전달받은 albumId와 ViewHolder의 albumId를 비교 하므로서 AlbumArt가 화면상에서 필요한지 확인 할수 있다.