2015-03-13 42 views
1

在以下情况下:使用AsyncTask的替代方法是什么?如何将图像加载到列表视图适配器中的正确行中

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

问题再次出现: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); 

    } 
+0

您可以使用piccasso库 – 2015-03-13 18:57:06

+0

正如问题所述:我想了解t他处理作品。但只是踢脚踢:我已经尝试过毕加索。 – 2015-03-13 18:58:52

回答

1

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

有不同的方法。我的解决方案是扩展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); 

    } 

然后withing适配器的时候应该调用loadRemoteImage(imageUri)

我也建议你使用位图缓存结合这个以加速获取图像和添加占位符的过程:)

+0

哇。我完全错过了如何解决这个问题。我不知道它在很多方面都牵涉其中,但在某些方面却很少。非常感谢你的完整答案。 – 2015-03-13 20:04:09

+0

这不会解决您的问题。您将看到闪烁的图像,因为第一次异步调用将完成并在第二次到达之前设置图像。它不会将逻辑放入适配器,而是放入派生视图中 - 这不是一个好设计。 – Matthias 2015-03-14 10:15:28

+0

我发现它更具可重用性,因为您不依赖于适配器..您可以使用完全相同的逻辑在任何位置加载远程图像。我也添加了占位符,而图像在我自己​​的代码中加载..无论如何,重要的部分是回收.. – LuTeddy 2015-03-16 12:33:27

3

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

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

+0

我没有使用这种方法,我没有测试它。但是这听起来正确,所以+1。谢谢。 – 2015-03-13 20:06:03

+1

好的。我收回之前说过的话。出于好奇,我尝试了你的方法,因为它简单得多。而且我能看到的效果最好。非常感谢你。我已经接受了其他答案。但是你的非常简单。谢谢。 – 2015-03-13 20:25:11

相关问题