【问题标题】:Image in listview ordering is not correct and download again列表视图排序中的图像不正确并重新下载
【发布时间】:2014-08-22 03:52:10
【问题描述】:

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

一些变量解释:

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

ImageLoader 是异步任务类,通过从 PostItem 获取图片 url 来下载图片

问题是,列表视图中图像的顺序不正确,例如图像应该出现在 1st 中,但同时出现在 1st 和 4th 中,如果我滚动,显示模式也会改变。

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

感谢您的帮助。

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

这是我生成列表视图的方式:

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;
    }
}

这里是imageloader,把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);
        }
    }

更新代码(实现 volley 库):

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;
    }

【问题讨论】:

  • 你能解释一下!post.imageURL.equals("null") &amp;&amp; viewHolder.img.getDrawable() == null 这行代码应该做什么吗?
  • !post.imageURL.equals("null") 表示部分 obj 没有 imageURL,因此需要在下载前检查,viewHolder.img.getDrawable() == null 表示视图是否为已分配图片,无需再次下载

标签: android image listview android-listview bitmap


【解决方案1】:

对于您尝试执行的任务,我强烈建议您使用 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 负责维护缓存和图像的顺序。

【讨论】:

  • 你需要提供这个缓存的实现,比如这个 public class BitmapLruCache extends LruCache implements ImageCache { //Override the methods here }
  • 谢谢,我实现了它,非常棒的库,它的加载速度比我自己写的 calss 快得多,但图像显示仍然相同,例如。第 1 张图片显示在第 4 个列表视图行中,有修复它的想法吗?谢谢
【解决方案2】:

如果您滚动列表视图,您将返回回收的convertview,它不为空,但它的图像视图不正确。 convertView 是通过滚动列表创建和回收的视图。这个视图减少了 GC 的调用,也为你节省了内存。它首先由您最早的列表项目分配。滚动列表后,例如列表的第一项消失并且您看到第 15 项,第一项的 convertView 再次传递给您。此时它不为空,它持有最后一个 imageview 的引用,即 item 1 的 imageview。

所以这是您的问题,您跳过了将正确的图像视图分配给您的viewHolder.img。 好的,你应该怎么做? 您可以做的最好的事情是在内存缓存中创建,通过它们的 URL 作为缓存的键来保存您下载的图像视图。在 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

如果您愿意,也可以使用 volley 库。

【讨论】:

  • 我已经实现了 volley lib,但是顺序问题似乎没有解决,知道吗?谢谢
  • @user782104 发布您在其中使用 volley 的 getView!
  • sorry 恐怕我弄糊涂了,getView用的viewHolder.img.setImageUrl(Constant.comment_imageFolder + post.imageURL, mImageLoader);获取图像
  • 在 getview 中更新 volley 库代码。我会在 15 分钟后回来
  • 除了这个下载图像代码我还需要什么?谢谢
【解决方案3】:
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 并尝试。看看有没有帮助。

【讨论】:

  • @user782104 好的,解释一下:Constant.comment_imageFolder + post.imageURL 你为什么使用+
  • post.imageURL 是图片名称,Constant.comment_imageFolder 是域名,例如"mydomain/img" + "1.jpg" 谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多