Android AsyncTask奇怪的行为

时间:2014-01-06 10:33:43

标签: android android-asynctask

我有一个ListFragment,可以异步加载多个图像,但它的表现方式很奇怪as you can see here

这是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在视频中的表现吗?

提前致谢

1 个答案:

答案 0 :(得分:4)

您可能正在循环中添加数据并在循环中调用notifyDataSetChanged(),或者您正在使用ArrayAdapters add()方法。您可能还会以不同于显示的顺序添加数据。

因此convertView被回收。这导致多次调用同一项的getView()。

这会导致BitmapWorkerClass的多个实例对同一个ImageView实例具有WeakReference。它们中的每一个都在某个时刻结束并调用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
    }