【问题标题】:How to load image into the correct row in a list view adapter如何将图像加载到列表视图适配器中的正确行
【发布时间】:2015-03-13 18:56:14
【问题描述】:

在以下情况下:我有什么替代使用 AsyncTask 的方法?

我正在使用 AsyncTask 将图像加载到适配器中。适配器行有许多 TextView 和一个 ImageView。 ImageView 是我加载图像的地方。图像正在从 Internet 加载。问题是当我滚动时,错误的图像会显示在一行/单元格中——直到正确的图像有时间到达。如何防止这种图像不匹配发生? 我问这个问题是因为我想了解它是如何工作的:我不只是想获得一些可能为我工作的库(我已经尝试过的许多库都失败了)。

问题又来了:AsyncTask 会导致图像加载到错误的行中,这样用户就可以清楚地看到图像正在寻找它们的最终目的地。

我希望问题很清楚。为了完整起见,下面是我在适配器的getView 方法中调用的方法来加载每个图像。该方法也在适配器内部。 使用 AsyncTask 的替代方法是什么?

private void loadImage(final ImageView photo, String imageUrl) {
        new AsyncTask<String, String, Bitmap>() {

            @Override
            protected Bitmap doInBackground(String... param) {
                try {
                    Bitmap b = callToServer(imageUrl);//takes long
                    return b;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }

            @Override
            protected void onPostExecute(Bitmap ret) {
                if (ret != null) {
                    photo.setImageBitmap(ret);
                }
            }

        }.execute(imageUrl);

    }

【问题讨论】:

  • 你可以使用 piccasso 库
  • 正如问题所说:我想了解这个过程是如何工作的。但只是为了好玩:我已经尝试过毕加索。

标签: android image listview android-asynctask adapter


【解决方案1】:

最常用的方法是使用您在适配器中创建的视图的 setTag(...) 和 getTag(...) 方法。创建后,您需要添加一个标签,该标签需要链接到随后异步加载的图像。该任务完成后,您可以检查视图的标签,如果它仍然与异步任务开始时相同,您可以设置图像。否则,您可以关闭图像。请记住,滚动时会重复使用相同的视图而不是创建视图。所以标签会改变。

这是一个很好的例子:Asynchronous Image Loader in Android ListView

【讨论】:

  • 我没有使用这种方法,也没有测试过。但这听起来是正确的,所以+1。谢谢。
  • 好的。我收回之前说过的话。出于好奇,我尝试了您的方法,因为它更简单。正如我所见,它的效果同样好。所以非常感谢。我已经接受了另一个答案。但是你的要简单得多。谢谢。
【解决方案2】:

问题在于行被回收,图像视图也是如此。然后当服务器响应返回时,图像视图已经属于另一个数据对象。

对此有不同的方法。我的解决方案是扩展 ImageView 并跟踪您要加载的图像。

class RemoteImageView extends ImageView {
   private String _uri;

   public synchronized void loadRemoteImage(String uri) {
       _uri = uri;
       loadImage(this, uri) ; //this is your async call
   }

  private synchronized void onImageLoaded(String uri, Bitmap image) {
       if(uri.equals(_uri)) {  //this will set only the correct image
            setImageBitmap(image);
       }
  } 

}

至于你的加载功能:

private void loadImage(final ImageView photo, final String imageUrl) {
        new AsyncTask<String, String, Bitmap>() {

            @Override
            protected Bitmap doInBackground(String... param) {
                try {

                    Bitmap b = callToServer(imageUrl);//takes long
                    return b;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }

            @Override
            protected void onPostExecute(Bitmap ret) {
                if (ret != null) {
                    photo.onImageLoaded(imageUri, ret);
                }
            }

        }.execute(imageUrl);

    }

然后使用您的适配器,您应该调用 loadRemoteImage(imageUri)

我还建议你将它与位图缓存结合起来,以加快获取图像和添加占位符的过程:)

【讨论】:

  • 哇。我完全错过了如何解决这个问题的重点。我不知道它涉及这么多——但在某些方面却如此之少。非常感谢您的完整回答。
  • 这不会解决您的问题。您将看到闪烁的图像,因为第一个异步调用将在第二个到达之前完成并设置图像。而且它不会将逻辑放入适配器中,而是放入派生视图中——这并不是一个好的设计。
  • 我发现它更易于重用,因为您不依赖适配器。您可以使用完全相同的逻辑在任何地方加载远程图像。我还在我自己的代码中加载图像时添加了占位符。无论如何,重要的部分是回收..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
相关资源
最近更新 更多