列表视图排序中的图像不正确并再次下载

时间:2014-08-22 03:52:10

标签: android image listview android-listview bitmap

以下是我如何设置列表视图以及如何通过下载来获取图像。

一些变量解释:

PostItem 是包含列表视图项数据的模型对象

ImageLoader 是通过从PostItem获取图片网址来下载图片的异步任务类

问题是,列表视图中图像的排序不正确,例如,第1个图像应出现在第1个,第4个,如果我滚动,则显示模式也会改变。

此外,如果我滚动,我发现图像会再次下载,即使我已检查过imageView是否有可绘制

感谢您的帮助。

=============================================== =====

以下是我生成listview的方法:

static class ViewHolderItem {
    TextView name;
    TextView date;
    ImageView img;
    TextView msg;
    TextView count;
    ImageView likeBtn;
    ImageView commentBtn;
    ImageView shareBtn;
}

private class MyPostAdapter extends ArrayAdapter<PostItem> {

    @Override
    public boolean isEnabled(int position) {
        return false;
    }

    public MyPostAdapter(Context context, int resource, List<PostItem> items) {
        super(context, resource, items);
    }

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

        View v = convertView;
        ViewHolderItem viewHolder;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.post_item, parent, false);

            viewHolder = new ViewHolderItem();
            viewHolder.name = (TextView) v.findViewById(R.id.postName);
            viewHolder.date = (TextView) v.findViewById(R.id.postDate);
            viewHolder.img = (ImageView) v.findViewById(R.id.postImg);
            viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
            viewHolder.count = (TextView) v.findViewById(R.id.count);
            viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
            viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
            viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
            v.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolderItem) convertView.getTag();
        }

        final PostItem post = getItem(position);

        if (post != null) {
            viewHolder.name.setText(post.name);

            try {
                c.setTime(sdf.parse(post.createDate));
            } catch (ParseException e) {
                e.printStackTrace();
            }

            relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
            viewHolder.date.setText(relative_date);

            viewHolder.msg.setText(post.txtMsg);
            viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));

            if (post.isLike) {
                viewHolder.likeBtn.setImageResource(R.drawable.like);
            } else {
                viewHolder.likeBtn.setImageResource(R.drawable.before_like);
            }

            if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
                new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
            } else {
                viewHolder.img.setImageDrawable(null);
            }

            viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    new APIManager("like", ctx, Constant.likeAPI + "/"
                            + post.commentID + "/" + userID, jsonListener,
                            getResources().getString(R.string.update_data));
                } 
            });

            viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
                    Intent i = new Intent(ctx, ReplyActivity.class);
                    i.putExtra("commentID", post.commentID);

                    // get reply list
                    for (PostItem reply : replyItemList) {
                        if (reply.postID.equals(post.commentID)
                                || reply.commentID.equals(post.commentID)) {
                            filterReplyList.add(reply);
                        }
                    }
                    i.putExtra("replyItemList", filterReplyList);
                    startActivityForResult(i, 0);
                }
            });

            viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent sendIntent = new Intent();
                    sendIntent.setAction(Intent.ACTION_SEND);
                    String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
                    sendIntent.putExtra(Intent.EXTRA_TEXT, data);
                    sendIntent.setType("text/plain");
                    startActivity(sendIntent);
                }
            });

        }
        return v;
    }
}

这是图像加载器,将imageview,url作为输入并将位图放在imageview中

public class ImageLoader extends AsyncTask<Object, Void, Bitmap> {

    private static String TAG = "ImageLoader";
    private InputStream input;
    private ImageView view;
    private ProgressBar loadingIcon;
    private ListView myListView;
    private String imageURL;
    private Context ctx;

    public ImageLoader(Context _ctx) {
        ctx = _ctx;
    }

    @Override
    protected Bitmap doInBackground(Object... params) {
        try {
            view = (ImageView) params[0];

            // handle Chinese characters in file name
//          String[] imgUrlArray = ((String) params[1]).split("/");
//          String fileName = imgUrlArray[imgUrlArray.length - 1];
//          String newfileName = URLEncoder.encode(fileName, "utf-8");
//          imageURL = ((String) params[1]).replace(fileName, newfileName);
            imageURL = ((String) params[1]);

            if (params.length > 2 && (ProgressBar) params[2] != null)
                loadingIcon = (ProgressBar) params[2];

            URL url = new URL(imageURL);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setDoInput(true);
            connection.connect();
            input = connection.getInputStream();

            final BitmapFactory.Options options = new BitmapFactory.Options();

            BufferedInputStream bis = new BufferedInputStream(input, 4*1024);
            ByteArrayBuffer baf = new ByteArrayBuffer(50);
            int current = 0;
            while ((current = bis.read()) != -1) {
                baf.append((byte)current);
            }
            byte[] imageData = baf.toByteArray();

            BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
            options.inJustDecodeBounds = true;
            options.inSampleSize = 2;
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (input != null)
                    input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        if (result != null && view != null) {
            if (loadingIcon != null)
                loadingIcon.setVisibility(View.GONE);
            view.setVisibility(View.VISIBLE);
            view.setImageBitmap(result);
        }
    }

更新了代码(实施排球库):

static class ViewHolderItem {
    TextView name;
    TextView date;
    NetworkImageView img;
    TextView msg;
    TextView count;
    ImageView likeBtn;
    ImageView commentBtn;
    ImageView shareBtn;
}

private class MyPostAdapter extends ArrayAdapter<PostItem> {

    @Override
    public boolean isEnabled(int position) {
        return false;
    }

    public MyPostAdapter(Context context, int resource, List<PostItem> items) {
        super(context, resource, items);
    }

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

        View v = convertView;
        ViewHolderItem viewHolder;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.post_item, parent, false);

            viewHolder = new ViewHolderItem();
            viewHolder.name = (TextView) v.findViewById(R.id.postName);
            viewHolder.date = (TextView) v.findViewById(R.id.postDate);
            viewHolder.img = (NetworkImageView) v.findViewById(R.id.postImg);
            viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
            viewHolder.count = (TextView) v.findViewById(R.id.count);
            viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
            viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
            viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
            v.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolderItem) convertView.getTag();
        }

        final PostItem post = getItem(position);

        if (post != null) {
            viewHolder.name.setText(post.name);

            try {
                c.setTime(sdf.parse(post.createDate));
            } catch (ParseException e) {
                e.printStackTrace();
            }

            relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
            viewHolder.date.setText(relative_date);

            viewHolder.msg.setText(post.txtMsg);
            viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));

            if (post.isLike) {
                viewHolder.likeBtn.setImageResource(R.drawable.like);
            } else {
                viewHolder.likeBtn.setImageResource(R.drawable.before_like);
            }

            if (!post.imageURL.equals("null")) {
                viewHolder.img.setImageUrl(Constant.comment_imageFolder + post.imageURL, mImageLoader);
            }

            viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    new APIManager("like", ctx, Constant.likeAPI + "/"
                            + post.commentID + "/" + userID, jsonListener,
                            getResources().getString(R.string.update_data));
                } 
            });

            viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
                    Intent i = new Intent(ctx, ReplyActivity.class);
                    i.putExtra("commentID", post.commentID);

                    // get reply list
                    for (PostItem reply : replyItemList) {
                        if (reply.postID.equals(post.commentID)
                                || reply.commentID.equals(post.commentID)) {
                            filterReplyList.add(reply);
                        }
                    }
                    i.putExtra("replyItemList", filterReplyList);
                    startActivityForResult(i, 0);
                }
            });

            viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent sendIntent = new Intent();
                    sendIntent.setAction(Intent.ACTION_SEND);
                    String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
                    sendIntent.putExtra(Intent.EXTRA_TEXT, data);
                    sendIntent.setType("text/plain");
                    startActivity(sendIntent);
                }
            });

        }
        return v;
    }

3 个答案:

答案 0 :(得分:3)

对于您尝试执行的任务,我强烈建议您使用Volley库。

here

阅读

您需要做的就是如下

mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());

mImageView.setImageUrl(BASE_URL + item.image_url, mImageLoader);

其中mImageViewcom.android.volley.NetworkImageView而不是常规ImageView

Volley负责维护缓存和图像的排序。

答案 1 :(得分:1)

如果滚动列表视图,您将返回回收convertview,它不是null,但它的图像视图不正确。 convertView是通过滚动列表创建和回收的视图。此视图可以减少GC调用并为您节省内存。它首先由您最早的清单项目分配。滚动列表后,例如列表中的第一项消失,您看到第15项,第一项的convertView再次传递给您。在这个时间它不是空的,它保留了最后一个imageview的参考,即项目1的图像视图。

所以这是您的问题,您跳过为viewHolder.img分配正确的imageview。 好的,你该怎么办? 您可以做的最好的事情是在内存缓存中创建,通过其URL作为缓存的键来保存您下载的imageview。在getview中检查缓存,如果它具有从中读取的当前imageview位置的URL并将其设置为viewHolder.img,则从Internet下载图像。

黄金法则是:

   ALWAYS OVERWRITE VIEWHOLDER VALUES WITH VALUES OF YOUR ITEM AT INDEX POSITON THAT

   GETVIEW PASSES TO YOU

如何创建缓存?看看Example LRU cache

http://developer.android.com/training/volley/request.html

如果你愿意,你也可以使用排球库。

答案 2 :(得分:0)

if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
                new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
}  

我猜这个问题就在这里。如果您获得的回收视图已经包含了之前使用的视图中的图像,会发生什么?这就解释了为什么图像在第1和第4位置出现以及滚动时显示模式的变化。

明白这一点?删除viewHolder.img.getDrawable() == null然后尝试。看看是否有帮助。