2014-01-06 6 views
1

У меня есть ListFragment, который загружает асинхронно несколько изображений, но он ведет себя странным образом, as you can see here.Android 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

, но мне нужно, чтобы обновить пользовательский интерфейс в GetView(), вы можете объяснить, что вы имеете в виду? – basteez

+0

Опубликуйте свой рецепт и весь код класса адаптера –

ответ

4

Вы, вероятно, добавляющие данные в цикле и вызова notifyDataSetChanged() в цикле или вы используете ArrayAdapters добавить метод(). Вы также можете добавить свои данные в другом порядке, чем показано.

Поэтому convertView перерабатывается. Это приводит к getView() для того же элемента, который будет вызываться несколько раз.

Это приводит к тому, что несколько экземпляров BitmapWorkerClass имеют значение WeakReference для одного экземпляра ImageView. Каждый из них заканчивается в какой-то момент и вызывает OnPostExecute(), вызывая эффект тасования.

Использование WeakReference (не рекомендуется кстати) помогает с утечками памяти, но это не поможет вам с 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() и поместить его после цикла. Или, если вы используете метод add() ArrayAdapters, переключитесь на addAll(). Если вы добавите код на свой вопрос, я могу рассказать вам больше. –

Смежные вопросы