为什么 ListView 中偶尔会加载错误的图像?

2024-02-17

我有一个列表视图,它以异步方式加载每个单元格中的图像。当我尝试缓慢向下滚动时(加载当前视图中的所有图像后),它可以完美地工作。 但是,当我尝试在加载它们之前向下滚动并向上滚动时,我遇到了这个问题。细胞开始显示与它们不对应的图像。

我的 getView 方法如下所示:

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

    // TODO Auto-generated method stub

    View rowView = null;

    if(convertView == null) {
        rowView = inflater.inflate(R.layout.list_posts_item, null);
        final Holder holder=new Holder();
        holder.tvTitle=(TextView) rowView.findViewById(R.id.tvTitleNamePost);
        holder.ivPrimaryImage=(ImageView) rowView.findViewById(R.id.ivPrimaryImage);
        holder.tvLocality=(TextView) rowView.findViewById(R.id.tvLocalityPosts);
        holder.tvDateCreated=(TextView) rowView.findViewById(R.id.tvDateCreated);
        rowView.setTag(holder);
    }else {
        rowView=convertView;
    }

    Holder holder = (Holder)rowView.getTag();
    holder.ivPrimaryImage.setId(position);
    holder.ivPrimaryImage.setTag(listOfPosts.get(position).getPostId());
    holder.ivPrimaryImage.setImageBitmap(null); // Added for flickering issue
    holder.tvTitle.setText(listOfPosts.get(position).getTitle());
    holder.tvLocality.setText(listOfPosts.get(position).getLocality());
    holder.tvDateCreated.setText(listOfPosts.get(position).getCreatedDate());
    postId = listOfPosts.get(position).getPostId();
    Image image = new Image();
    image.setImg(holder.ivPrimaryImage);

    if (!"N".equalsIgnoreCase(listOfPosts.get(position).getHasImage()) ) {
        if(!tagsCaching.containsKey(postId))
            new GetPrimaryImages().execute(image);
        else
             holder.ivPrimaryImage.setImageBitmap(tagsCaching.get(postId));
    }

    return rowView;
}

我的异步调用类如下所示:

public class GetPrimaryImages extends AsyncTask<Image, Void, Bitmap> {

ImageView imageView = null;
    protected Bitmap doInBackground(Image... images) {
    this.imageView=images[0].getImg();



        // Building Parameters
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("postid",(String)(this.imageView.getTag()) ));


             json = jsonParser.makeHttpRequest(CommonResources.getURL("get_primary_image"),
                    "POST", params);


        if(json == null){
            return null;
        }
        Log.d("Fetching Image",imageView.getTag()+ json.toString());
        tagsDownloaded.add((String)imageView.getTag());
        // check for success tag
        String TAG_SUCCESS = "success";
        try {
            int success = json.getInt(TAG_SUCCESS);

            if (success == 0) {
               image =  json.getString("primaryimage");

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return getImage(image);

    }

    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(Bitmap result) {
        tagsCaching.put((String)imageView.getTag(), result);
        imageView.setImageBitmap(result);

    }

    public Bitmap getImage(String imageString) {
        if("null".equalsIgnoreCase(imageString)){
            return null;
        }else{
            byte[] decodedString = Base64.decode(imageString, Base64.DEFAULT);
            Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
            //image.setImageBitmap(decodedByte);
            return decodedByte;
        }

    }


}

Edit:

我向 Holder 添加了一个新的实例变量:

public class Holder
{
    TextView tvTitle;
    ImageView ivPrimaryImage;
    TextView tvLocality;
    TextView tvDateCreated;
    int position;
}

在 getView 中设置相同的: 持有者.position = 位置; 并将持有者对象传递给异步任务: new GetPrimaryImages(位置,持有者).execute(图像);

并修改Async调用类如下: 1.http调用添加cancel 2.更改了onPostExecute方法

  public class GetPrimaryImages extends AsyncTask<Image, Void, Bitmap> {

    int mPosition;
    Holder mHolder;
    public GetPrimaryImages(int position, Holder holder){
        mPosition = position;
        mHolder = holder;
    }

    ImageView imageView = null;
    protected Bitmap doInBackground(Image... images) {
    this.imageView=images[0].getImg();



        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("postid",(String)(this.imageView.getTag()) ));


        JSONObject json;
        if(mHolder.position == mPosition)
             json = jsonParser.makeHttpRequest(CommonResources.getURL("get_primary_image"),
                    "POST", params);

        else {
            json = null;
            cancel(true);
        }

        // check log cat fro response
        if(json == null){
            return null;
        }
        Log.d("Fetching Image",imageView.getTag()+ json.toString());
        tagsDownloaded.add((String)imageView.getTag());
        // check for success tag
        String TAG_SUCCESS = "success";
        try {
            int success = json.getInt(TAG_SUCCESS);

            if (success == 0) {
               image =  json.getString("primaryimage");

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return getImage(image);

    }


    protected void onPostExecute(Bitmap result) {
        if (mHolder.position == mPosition) {
            tagsCaching.put((String) imageView.getTag(), result);
            imageView.setImageBitmap(result);
        }

    }

    public Bitmap getImage(String imageString) {


        //needs to wait
        if("null".equalsIgnoreCase(imageString)){
            return null;
        }else{
            byte[] decodedString = Base64.decode(imageString, Base64.DEFAULT);
            Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
            //image.setImageBitmap(decodedByte);
            return decodedByte;
        }

    }


}

似乎正在发挥作用。 :)

现在我的疑问是缓存图像的最佳方法是什么?应该将其写入文件吗?每次我向上滚动时都会从中读取它?


问题是,当您的异步任务结束其后台操作时,它链接到的元素已被回收以保存集合中的另一个元素。

让我们关注元素位置,假设您的列表视图最多可以显示 4 个元素。

列表视图第一次调用 getview 获取前 4 个元素,并创建并运行四个异步任务。 然后滚动到显示位置 11 - 15,第一个元素(与位置 1 相关的元素)在异步任务结束之前被回收到位置 11。

然后asynctask结束,你看到的是与post 11相关的图像和与post 1相关的位图。

避免这种情况的一种方法是在 asynctask 中知道视图已被回收,正如 Lucas Rocha 的这篇旧文章中所建议的那样。

列表视图的性能技巧 http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/

查看帖子以了解有关列表视图如何工作的见解:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 ListView 中偶尔会加载错误的图像? 的相关文章

  • 如何强制下载图片?

    我的页面上有一个动态生成的图像 如下所示 img src 我不想告诉我的用户右键单击图像并点击保存 而是想公开一个下载链接 单击该链接将提示下载图像 如何实现这一目标 最初我在 js 中尝试这样做 var path my image att
  • R - 加速近似日期匹配。 idata.frame?

    我正在努力有效地执行两个数据帧之间的 关闭 日期匹配 这个问题探索了一个解决方案 使用idata frame来自plyr包 但我也对其他建议的解决方案感到非常满意 这是两个数据框的非常简单的版本 sampleticker lt data f
  • Powershell 中的“$”是什么?

    是什么意思 在 Powershell 中 Edit TechNet 答案 http technet microsoft com en us library hh847768 aspx同义反复 没有解释 成功 或 失败 的含义 包含上次操作的
  • 如何将 SQL“LIKE”与 LINQ to Entities 结合使用?

    我有一个文本框 允许用户指定搜索字符串 包括通配符 例如 Joh Johnson mit ack on 在使用 LINQ to Entities 之前 我有一个存储过程 该存储过程将该字符串作为参数并执行以下操作 SELECT FROM T
  • CUDA 添加矩阵的行

    我试图将 4800x9600 矩阵的行加在一起 得到一个 1x9600 的矩阵 我所做的是将 4800x9600 分成 9 600 个矩阵 每个矩阵长度为 4800 然后我对 4800 个元素进行缩减 问题是 这真的很慢 有人有什么建议吗
  • AWK 错误:尝试在标量上下文中使用数组

    我正在学习AWK 这是一个简单的代码片段 我尝试将字符串拆分为数组并迭代它 BEGIN split a b c a for i 1 i lt length a i print a i 运行此代码时 我收到以下错误 awk awk txt 4
  • 突出显示单词并提取其附近文本的函数

    我有一个文本例如 Etiam porta semmalesuada magna mollis euismod 整数取数 ante venenatis dapibus posuere velit aliquet 埃蒂亚姆 门塔 塞姆 male
  • [GoF]-ConcreteSubject 可以覆盖通知方法吗?

    我正在模拟一种情况 其中存在 通知框 观察者 list1 list2 list3 这个科目 现在我会制作一张图表 其中使用观察者模式描述每个列表实现不同类型的notify 这一事实 例如 列表状态的某些变化只需要按照某些标准通知给某些观察者
  • 拉斐尔路径交叉点不起作用

    我对拉斐尔和 pathIntersection method JSFiddle 示例 http jsfiddle net t6gWt 2 您可以看到有两条线都与曲线相交 但当我使用 pathIntersection method 有一个未解
  • 缓存感知树的实现

    I have a tree where every node may have 0 to N children 用例是以下查询 给定指向两个节点的指针 这些节点是否位于树的同一分支内 Examples q 2 7 gt true q 5 4
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include
  • 无法完成添加 Android 证书的构建

    我刚刚完成构建我的应用程序 我发送了一个没有证书的构建版本 它工作了 现在添加一个 android 证书 它在我的代号 one 仪表板上报告构建错误 如有帮助 将不胜感激 失败 构建失败并出现异常 出了什么问题 执行 任务失败 transf
  • 在引导程序中以编程方式更改选项卡窗格选项卡

    我使用的选项卡窗格定义为 ul class nav nav tabs li a href personal Personal Information a li li class active a href contact Contact a
  • 对齐与未对齐 x86 SIMD 指令之间的选择

    SIMD指令一般有两种类型 A 使用对齐的内存地址 如果地址未在操作数大小边界上对齐 则会引发一般保护 GP 异常 movaps xmm0 xmmword ptr rax vmovaps ymm0 ymmword ptr rax vmova
  • 在并行包中的 R 的 par*apply 函数内部使用 Rcpp 函数

    我试图了解背后发生的事情Rcpp sourceCpp 调用并行环境 最近 问题中部分解决了这个问题 在 Windows 上使用 parLapply 中的 Rcpp 函数 https stackoverflow com questions 2
  • NSUserDefaults、Settings.bundle 和应用程序组

    我有一个有 2 个目标的应用程序 主应用程序和 Today 扩展 为了在这些目标之间共享设置 我打开了应用程序组功能 添加了一个组group myApp com然后使用NSUserDefaults在主应用程序和今日扩展中都是如此 var d
  • React Native 0.61 中引入的快速刷新不起作用

    也发表在https github com facebook react native issues 27583 https github com facebook react native issues 27583 更新 一天过去了 我再次
  • 使用 numpy 加速 for 循环

    下一个 for 循环如何使用 numpy 获得加速 我想这里可以使用一些奇特的索引技巧 但我不知道是哪一个 这里可以使用 einsum 吗 a 0 for i in range len b a numpy mean C d e f b i
  • 使用未分配的局部变量

    我遇到了一个错误 尽管声明了变量 failturetext 和 userName 错误仍然出现 谁能帮帮我吗 Use of Unassigned local variable FailureText Use of Unassigned lo
  • 将 R 中的列中的单引号替换为双引号

    我在 R 中的数据框有一个 A 列 其中有带单引号的字符串数据 Column A Hello World Hi World Good morning world 我想做的是将单引号替换为双引号并实现如下所示的输出 Column A Hell

随机推荐