【问题标题】:How can I prevent images in this Android listview from shifting around when I click on other screen elements?当我单击其他屏幕元素时,如何防止此 Android 列表视图中的图像移动?
【发布时间】:2010-11-26 17:29:32
【问题描述】:

我早些时候就这个主题发表了另一篇文章,但后来我根据建议稍微更改了我的代码,但存在同样的问题。如果我单击屏幕上的其他元素,我的图像会不断移动。

这是我调用的代码:

new Thumbnailer(image_main, image_table).execute(image);

image_main 是我的 imageView,而 image_table 是保存它的表。

 private class Thumbnailer extends AsyncTask<String, Void, Bitmap> {
      private ImageView imageView;
      private TableLayout imageTable;

        public Thumbnailer(ImageView imageView, TableLayout imageTable) {
            this.imageView = imageView;
            this.imageTable = imageTable;
        }

  @Override
  protected void onPostExecute(Bitmap result) {
      imageView.setImageBitmap(result);
               imageView.setVisibility(View.VISIBLE);
               imageTable.setVisibility(View.VISIBLE);
  }
  @Override
      protected void onProgressUpdate(Void... progress) {
      }

  @Override
  protected Bitmap doInBackground(String... params) {
         BitmapFactory.Options o = new BitmapFactory.Options();
          o.inJustDecodeBounds = true;
          BitmapFactory.decodeFile(params[0], o);
          final int REQUIRED_SIZE=70;

          //Find the correct scale value. It should be the power of 2.
          int width_tmp=o.outWidth, height_tmp=o.outHeight;
          int scale=1;
          while(true){
              if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                  break;
              width_tmp/=2;
              height_tmp/=2;
              scale++;
          }
          //Decode with inSampleSize
          BitmapFactory.Options o2 = new BitmapFactory.Options();
          o2.inSampleSize=scale;       
          return BitmapFactory.decodeFile(params[0], o2);
  }
 }

【问题讨论】:

    标签: android android-listview android-asynctask


    【解决方案1】:

    我遇到了类似的问题。我会通过 AsyncTask 将图像加载到 ListView 中(它可能会通过 HTTP 获取图像),并且它似乎在加载正确的图像之前加载了错误的图像一瞬间。就好像 Android 在 HTTP 请求完成之前重用了该行,并且 AsyncTasks 有点冲突。

    上面的 cmets 证实了正在发生的事情。

    我通过在 AsyncTask 启动之前将图像路径放在 ImageView 的标签中来修复它,然后在 AsyncTask 完成后但在它调用 setImageBitmap 之前检查该标签。

    添加这些行:

    final String somethingUnique = "put the image path or some other identifier here";
    image_main.setTag(somethingUnique);
    

    在这一行之前:

    new Thumbnailer(image_main, image_table).execute(image);
    

    现在,在 onPostExecute 中,检查标签:

    // if this does not match, then the view has probably been reused
    if (((String)imageView.getTag()).equals(somethingUnique)) {
      imageView.setImageBitmap(result);
    }
    

    【讨论】:

      【解决方案2】:

      听起来您被视图回收所困扰。也就是说,当您在 Android 中滚动列表时,它不会创建新行,而是重用屏幕外的行。在这种情况下,这可能会导致多个任务尝试将图像加载到单个图像视图中。您实际上需要能够以某种方式判断哪一个加载请求是最近的一行并取消较早的请求/忽略它们的结果,或者只是使用为您处理此问题的库(如droid-fu)。

      您也可以在适配器中关闭视图回收(这是在 getView 方法中使用 convertView 参数的部分),但请注意,这会使列表滚动缓慢且不稳定,尤其是在旧设备上。

      【讨论】:

      • 感谢您的回复。我当前的实现只是在 getView 中进行位图解码,它本身工作正常,但速度慢且滞后。我实际上一直在看这个android-developers.blogspot.com/2010/07/… 我认为我需要一些如何处理并发部分的东西?不太确定。我的java技能不是很好哈哈。
      • 它比这更有趣。您无法保证最近一次调用 getView 返回的视图是最终出现在屏幕上的视图。 ListView 和 GridView 有时会出于测量目的使用剪贴视图。异步加载的一个简单解决方案是通过适配器位置而不是最终目标视图来跟踪加载的元素应该去哪里。 listView.getChildAt(position - listView.getFirstVisiblePosition()) 将始终为您提供正确的当前项目视图,假设它在范围内并在屏幕上。 (检查 0
      • 我明白你在说什么,但我只是没有运气让它工作
      • 在您链接到的那篇博客文章中,相关部分是当在同一视图上启动新下载时,他们会取消 ImageView 上的挂起下载。他们这样做是因为否则异步任务 - 可能以任何顺序返回 - 最终可能会相互踩踏,尤其是在视图回收时。 (顺便说一句——您是否有理由在这里滚动自己的实现而不使用开发人员博客文章中的那个?如果您并不真正了解视图回收和线程所涉及的问题,那么您只是在问痛苦和苦难。)
      • 我已经根据博客更新了相同的行为。我错过了什么吗?代码:pastebin.com/7EmuWhdv
      【解决方案3】:

      这个Android Developer's blog post为此提供了一个参考项目。只需将项目中的http图片下载代码改成你的doInBackground代码即可。

      【讨论】:

        猜你喜欢
        • 2016-07-09
        • 2011-12-04
        • 2014-01-08
        • 2021-02-07
        • 2021-12-12
        • 2015-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多