ListView滚动时,图片混乱

5

我有一个ListView,其中包含两个TextView和一个ImageView。这些图像是从互联网加载的,并且由LruCache进行缓存。当滚动ListView时,图像会在几秒钟内被混淆。直到正确的图像完全加载之前,不应该有任何图像显示。我找到了一些具有相同问题的问题,但没有人帮助我 :/.这是我的代码:

public class NewsAdapter extends BaseAdapter {
    private static LayoutInflater inflater;
    private List<Item> items = new LinkedList<Item>();
    private LruCache<String, Bitmap> mMemoryCache;

    public NewsAdapter(Context context) {
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        // Bitmap Cache
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return getSizeInBytes(bitmap) / 1024;
            }
        };
    }

    public void add(Item item) {
        items.add(item);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = new ViewHolder();
        if(convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_item, null);
            viewHolder.ivPic = (ImageView) convertView.findViewById(R.id.ivPic);
            viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
            viewHolder.tvShortDesc = (TextView) convertView.findViewById(R.id.tvShortDesc);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        final Item item = items.get(position);
        viewHolder.tvTitle.setText(item.getTitle());
        viewHolder.tvShortDesc.setText(Html.fromHtml(item.getShortDesc()));

        Bitmap bitmap = mMemoryCache.get(item.getPicUrl());
        if (bitmap != null) {
            viewHolder.ivPic.setImageBitmap(bitmap);
        } else {
            GetBitmap gb = new GetBitmap(item.getPicUrl(), viewHolder.ivPic);
            gb.execute();
        }

        return convertView;
    }

    static class ViewHolder {
        ImageView ivPic;
        TextView tvTitle;
        TextView tvShortDesc;
    }

    @Override
    public int getCount() {
        return items.size();
    }

    @Override
    public Item getItem(int position) {
        return items.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @SuppressLint("NewApi")
    public static int getSizeInBytes(Bitmap bitmap) {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            return bitmap.getByteCount();
        } else {
            return bitmap.getRowBytes() * bitmap.getHeight();
        }
    }

    private class GetBitmap extends AsyncTask<Void, Bitmap, Bitmap> {
        private String url;
        private ImageView ivPic;

        public GetBitmap(String url, ImageView ivPic) {
            this.url = url;
            this.ivPic = ivPic;
        }

        @Override
        protected Bitmap doInBackground(Void... params) {
            Bitmap bitmap = null;
            try {
                URL url = new URL(this.url);
                bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
            } catch (Exception e) {
                e.printStackTrace();
            }

            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (bitmap != null) ivPic.setImageBitmap(bitmap); 
        }

    }

}

如果有人有想法,那就太好了...提前谢谢!

P.S.: 我忘了一件事,请不要建议任何库,我想在没有任何外部库的情况下完成它。


这与视图回收和图像放置错误有关。请查看此链接:http://developer.android.com/training/displaying-bitmaps/process-bitmap.html - tyczj
尝试移除这里的final关键字:Item item = items.get(position); - Ilya Demidov
你需要在情况(bitmap == null)下放置占位图像。 - njzk2
每次图像未加载时(当您启动GB时)都会发生这种情况。 - njzk2
@zeitgeist:抱歉有些含糊,我指的是在getView中的测试。 - njzk2
显示剩余4条评论
2个回答

3
public GetBitmap(String url, ImageView ivPic, int position) {
    this.url = url;
    this.ivPic = ivPic;
    this.position = position;
    ivPic.setTag(position);
    ivPic.setImageBitmap(null);
}

@Override
protected void onPostExecute(Bitmap bitmap) {
     super.onPostExecute(bitmap);
     if(bitmap != null && ((Integer)getTag) == this.position)
         ivPic.setImageBitmap(bitmap); 
}

问题在于您没有检查图像是否在相同的位置。尝试使用上述代码,希望能有所帮助。

非常好!如果我快速滚动,仍然会有一个错误的图像出现半秒钟左右,但比以前好多了! - user2351519
太好了!非常感谢!现在一切都按照预期运行 :))。 - user2351519
我真的不理解(整数)getTag....这里的getTag是什么?它不应该与ImageView相关联,如iv.getTag()吗? - Pushan Gupta
@Vidor 是的,它是视图标签,需要加载图像。 - Triode

0

可能是这段代码片段

 ViewHolder viewHolder = new ViewHolder();

每次调用getView时都会创建一个新的viewHolder实例。

尝试使用这个方法:

   final ViewHolder viewHolder;

然后在if结构中

    viewHolder = new ViewHolder();

在你的代码中实现:

  @Override
public View getView(int position, View convertView, ViewGroup parent) {
   final ViewHolder viewHolder; 

    if(convertView == null) {
        convertView = inflater.inflate(R.layout.list_item_item, null);
        viewHolder = new ViewHolder();
        viewHolder.ivPic = (ImageView) convertView.findViewById(R.id.ivPic);
        viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
        viewHolder.tvShortDesc = (TextView) convertView.findViewById(R.id.tvShortDesc);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    final Item item = items.get(position);
    viewHolder.tvTitle.setText(item.getTitle());
    viewHolder.tvShortDesc.setText(Html.fromHtml(item.getShortDesc()));

    Bitmap bitmap = mMemoryCache.get(item.getPicUrl());
    if (bitmap != null) {
        viewHolder.ivPic.setImageBitmap(bitmap);
    } else {
        GetBitmap gb = new GetBitmap(item.getPicUrl(), viewHolder.ivPic);
        gb.execute();
    }

    return convertView;
}

谢谢,你是对的,你的解决方案更好。但这不是问题所在。问题在我实现整个ViewHolder之前就出现了。 - user2351519
1
每次调用getView时都创建一个新的viewHolder实例是浪费内存的。 - Björn Hallström

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接