2014-01-06 96 views
1

我有一個ListFragment異步加載多個圖像,但它的行爲奇怪的方式,as you can see hereAndroid AsyncTask奇怪的行爲

這裏的的AsyncTask代碼

public class BitmapWorkerClass extends AsyncTask<Integer, Void, Bitmap> 
{ 
    private Context context; 
    private final WeakReference<ImageView> imageViewWeakReference; 
    private int data = 0; 
    public BitmapWorkerClass(ImageView imageView, Context context) 
    { 
     this.context = context.getApplicationContext(); 
     imageViewWeakReference = new WeakReference<ImageView>(imageView); 
    } 

    @Override 
    protected Bitmap doInBackground(Integer... params) { 
     data = params[0]; 
     return ImageResizer.decodeSampledBitmapFromResource(context.getResources(),  data, 100,100); 
    } 

    @Override 
    public void onPostExecute(Bitmap bitmap) 
    { 
     if(imageViewWeakReference != null && bitmap != null) 
     { 
      final ImageView imageView = imageViewWeakReference.get(); 
      if(imageView != null) 
      { 
       imageView.setImageBitmap(bitmap); 
      } 
     } 
    } 
} 

,我把它從ListFragment適配器的getView()方法

public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder = null; 
    if(convertView == null) 
    { 
     LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = inflater.inflate(R.layout.list_fragment_single_recipe_title, null); 
     holder = new ViewHolder(); 

     holder.image = (ImageView) convertView.findViewById(R.id.recipeTitleImage); 
     holder.title = (TextView) convertView.findViewById(R.id.recipeTitleText); 
     convertView.setTag(holder); 
    } 
    else 
    { 
     holder = (ViewHolder) convertView.getTag(); 
    } 
    Recipe recipe = getItem(position); 
    loadBitmap(recipe.getImage(), holder.image); 
    holder.title.setText(recipe.getTitle()); 
    return convertView; 

public void loadBitmap(int resId, ImageView imageView) 
{ 
    BitmapWorkerClass task = new BitmapWorkerClass(imageView, getContext()); 
    task.execute(resId); 
} 

你能幫助我理解是什麼使的AsyncTask表現爲視頻?

在此先感謝

+0

的事實是,有沒有保證getView多少次叫 – Blackbelt

+0

但我需要更新UI進入getView(),你能解釋一下你的意思? – basteez

+0

發佈你的食譜和整個適配器類代碼 –

回答

4

你可能在一個循環中添加數據和循環中調用notifyDataSetChanged(),或者你正在使用ArrayAdapters add()方法。您可能還會按照與顯示順序不同的順序添加數據。

因此convertView被回收。這會導致getView()多次調用同一個項目。

這會導致BitmapWorkerClass的多個實例擁有一個WeakReference指向ImageView的同一個實例。他們每個人都在某個時間完成並調用OnPostExecute(),導致隨機播放效果。

使用WeakReference(不推薦btw)有助於解決內存泄漏問題,但它無助於View-recycling。下面的代碼應該解決您的問題,但它可能不是最有效的方法。

public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder = null; 
     if(convertView == null) 
     { 
      LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = inflater.inflate(R.layout.list_fragment_single_recipe_title, null); 
      holder = new ViewHolder(); 

      holder.image = (ImageView) convertView.findViewById(R.id.recipeTitleImage); 
      holder.title = (TextView) convertView.findViewById(R.id.recipeTitleText); 
      convertView.setTag(holder); 
     } 
     else 
     { 
      holder = (ViewHolder) convertView.getTag(); 
     } 
     Recipe recipe = getItem(position); 
     // cancel the previous asynctask if there was any 
     if (holder.asynctask != null) { 
      holder.asynctask.cancel(false); 
      // you could pass true, but would have to handle the interruption then 
     } 
     // remove the previous image, you could set a default or loading image here instead 
     holder.image.setImageDrawable(null); 
     holder.asynctask = loadBitmap(recipe.getImage(), holder.image); 
     holder.title.setText(recipe.getTitle()); 
     return convertView; 
    } 

    public BitmapWorkerClass loadBitmap(int resId, ImageView imageView) 
    { 
     BitmapWorkerClass task = new BitmapWorkerClass(imageView, getContext()); 
     task.execute(resId); 
     return task; 
    } 

    public static class ViewHolder { 
     ImageView image; 
     TextView title; 
     BitmapWorkerClass asynctask; // save a reference to the asynctask 
    } 
+0

解決了我的問題,非常感謝! P.S .:不要擔心效率,這是一個示例應用程序的代碼,我不需要它是完美的;-) – basteez

+0

好聽。您可以輕鬆地將notifyDataSetChanged()拉出並放置在循環之後。或者,如果您使用的是ArrayAdapters的add()方法,請切換到addAll()。如果你將代碼添加到你的問題中,我可以告訴你更多。 –