2011年4月27日水曜日

ListViewのadapterでAsyncTaskを使って画像DownloadしてImageViewに乗せるとスクロール時にズレる問題について

以下のようなadapterを作ってみた

    public class ImageListAdapter extends ArrayAdapter<String>{
        private ArrayList<String> urls;
        private LayoutInflater inflater;
    
public UserListAdapter(Context context, int textViewResourceId,
ArrayList<String> urls) {
       super(context, textViewResourceId, users);
       this.urls = urls;
       this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   }

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

       if (view == null) {
           view = inflater.inflate(R.layout.row_status, null);
       }

       String url = urls.get(position);
       if (user != null) {
           ImageView imageview = (ImageView) view.findViewById(R.id.image);
         
           /*//コンストラクタでImageView送ってその後executeでURL送る
           DownloadTask task = new DownloadTask(imageview);
           try {
               task.execute(url);
           } catch (RejectedExecutionException e) {
}
*/

           /*//ImageViewにURLをタグを乗せてAsynctask起動
           GetImageInBackground task = new GetImageInBackground();
           imageview.setTag(url);
           try {
               task.execute(imageview);
           } catch (RejectedExecutionException e) {
}
*/

       }
       return view;
}
    }
  
  
で、以下それぞれのタスク
public class DownloadTask extends AsyncTask<String, Void, Bitmap> {
    // アイコンを表示するビュー
    private ImageView imageView;

    // コンストラクタ
    public DownloadTask(ImageView imageView) {
        this.imageView = imageView;
    }
  

    // バックグラウンドで実行する処理
    @Override
    protected Bitmap doInBackground(String... urls) {
        Log.v("AsyncTastTest", "DownloadTask doInBackground" + " urls[0] =" + urls[0]);
     Bitmap image = ImageCache.getImage(urls[0]);
        if (image == null) {
           image = HttpClient.getImage(urls[0]);
           ImageCache.setImage(urls[0], image);
        }
        return image;
}

    // メインスレッドで実行する処理
    @Override
    protected void onPostExecute(Bitmap result) {
        Log.v("AsyncTastTest", "DownloadTask onPostExecute");
        this.imageView.setImageBitmap(result);
    }
}

public class GetImageInBackground extends AsyncTask<ImageView , ImageView , Long > {
    Bitmap bitmap;
    String tag;

    @Override
    protected void  onProgressUpdate  (ImageView... params){
    if (bitmap!=null){
              ImageView imageViewByTag = (ImageView) params[0].findViewWithTag(tag);
              if (imageViewByTag != null) {
                  imageViewByTag.setImageBitmap(bitmap);
                }
      }
    }

    @Override
    protected Long doInBackground(ImageView... params) {
        tag = (String) params[0].getTag(); //タグからurl引っ張る
        if (tag==null){
            bitmap = BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.icon);//デフォ画像
        }else{
         bitmap = ImageCache.getImage(tag);
            if (bitmap == null) {
                bitmap = HttpClient.getImage(tag);
                ImageCache.setImage(tag, bitmap);
            }
        }
        publishProgress(params[0]);
        return null;
    }
}

HttpClientのclassとImageCacheとかは以下から引っ張ってきて下さい
"AsyncTaskでユーザビリティを向上させる"
http://labs.techfirm.co.jp/android/cho/1079
前者のDownloadTaskもそのまま使わせてもらっています。


           /*//コンストラクタでImageView送ってその後executeでURL送る
           DownloadTask task = new DownloadTask(imageview);
           try {
               task.execute(url);
           } catch (RejectedExecutionException e) {
}
*/
こっちのタスクを使う場合、実機で高速にスクロールしたりすると画像が違うrowに格納されたりズレたりします。
Logを取ってみた所、たまにonPostExecuteされていない場合があるみたい?それによってpositionとの対応関係がズレるって現象が起きちゃうみたいです。
別にRejectedExecutionException発生してなかったりするんですが・・・もっと細かくログ取って調査したほうがいいかな。
解決方法はどうにかなってるので気が向いたらで。

           /*//ImageViewにURLをタグを乗せてAsynctask起動
           GetImageInBackground task = new GetImageInBackground();
           imageview.setTag(url);
           try {
               task.execute(imageview);
           } catch (RejectedExecutionException e) {
}
*/
こちらの場合ImageViewにタグを乗せて送っているので対応関係がズレる可能性がなくなる。

実は後者でも何か若干動作怪しい場合があります。
もうちょっと色々やる余地はあるのかな?

0 件のコメント:

コメントを投稿