如何从Android ListView中的URL最佳加载图像

时间:2018-10-12 14:46:14

标签: android listview

所以一段时间以来,我一直在努力用最佳方法在Android的ListView中加载图像。

图像来自服务器,因此可能需要一些时间来加载。据我了解,只有两种方法可以实现此目的:

1-在主线程上加载图像-这会导致视图显示和滚动时立即显示正确的图像,但滚动性能较差,并可能导致应用挂起和崩溃。

2-将图像加载到AsyncTask中。这意味着列表显示或滚动时图像将为空白,但最终显示。由于列表完成了缓存,因此您还可以获得错误的图像。但这可以提供良好的性能和滚动效果,并且不会挂起/崩溃。

似乎两种解决方案均无法正常工作。必须有一个可行的解决方案??我看过其他这样的帖子,但答案似乎总是1或2,但都不是一个好的解决方案...

我的列表适配器代码如下。 HttpGetImageAction.fetchImage()方法要么执行异步任务,要么根据我设置的标志在主线程上获取图像。加载完图像后,我还会在本地和磁盘上缓存图像,因此问题主要发生在第一次(但是缓存仅用于100张图像,并且列表有1000s)

ConcurrentModificationException

9 个答案:

答案 0 :(得分:4)

切勿在主线程上加载图像。任何网络调用都应异步进行,并且不应在主线程上进行。您的图像可能会快速加载(在主线程上),因为您可能具有良好的Internet连接,图像较小和/或图像较少。但是,想象一下,如果使用您的应用程序的人的互联网速度较慢,然后有一天您的列表增加到数百个,会发生什么!

下面的方法是加载滚动视图内容的公认方法

  • a)在加载滚动视图时加载文本内容。再次,加载应该异步完成,但是您可以显示加载视图,直到下载完成
  • b)显示图片 图像在每个单元格上加载时的占位符
  • c)加载图像 异步

使用像Picasso这样的库将极大地帮助您,因为您需要处理很多样板代码,否则就需要处理

  • 当单元被重复使用时取消图像下载,并且
  • 开始为重复使用的单元格下载新文件
  • 缓存
  • 重试下载失败

希望这会有所帮助。

答案 1 :(得分:0)

使用Glide [https://github.com/bumptech/glide]或Picasso [http://square.github.io/picasso/]-这两个库非常相似,并且易于使用,具有缓存,在后台工作,允许占位符等。 用法很简单:

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

答案 2 :(得分:0)

简单的解决方案:滑行。

  

Glide是一种快速有效的开源媒体管理和映像   Android的加载框架,用于包装媒体解码,内存和   磁盘缓存和资源池化成一个简单易用的   接口。 Glide支持获取,解码和显示视频   静止图像,图像和GIF动画。

您可以像这样加载图像:

GlideApp.with(context)
    .load("http://via.placeholder.com/300.png")
    .into(imageView);

有关更多信息,请参阅:

https://guides.codepath.com/android/Displaying-Images-with-the-Glide-Library https://github.com/bumptech/glide

答案 3 :(得分:0)

使用Glide库。Google推荐。

第1步:

使用最新的Glide版本4依赖项(https://github.com/bumptech/glide

  

实现'com.github.bumptech.glide:glide:4.8.0'

     

annotationProcessor'com.github.bumptech.glide:compiler:4.8.0'

第2步:

 Glide.with(MainActivity.this)
        .load(url)
        .apply(new RequestOptions().placeholder(R.drawable.placeholder).error(R.drawable.error_image))//this line optional - you can skip this line
        .into(imageview);

答案 4 :(得分:0)

使用毕加索或Glide库 这些库的作用是,它们从u映像url并下载并将其保存在缓存中,这样,每当您再次打开同一映像时,它将加载得更快,并且会阻止网络的使用

毕加索 http://square.github.io/picasso/

滑翔 https://github.com/bumptech/glide

答案 5 :(得分:0)

您可以尝试非常快速且经过优化的UnivarsalImageLoader。 它支持多线程图像加载(异步或同步)和高级别的自定义。

google web tool to signed url

答案 6 :(得分:0)

这是我的方法

首先,我总是创建一个RecyclerView.ViewHolder,并向其中传递一个Func<int, Bitmap> image_provider(或者您可以传递某种形式的lamda?),如果调用该函数,它将检索特定ID的图像(如果不能)。将显示默认的加载图片

所有内容都存储在一个片段中(我称之为DataFragment),该片段的retainstate设置为true。

首先加载一个json对象列表,该列表告诉我必须显示哪些图像,这种情况发生在数据片段内部,因此如果配置发生更改,它将继续显示

我使用类似SetItems(MyImages)的方法将该信息发送到适配器

然后我启动一个新线程,该线程将加载图像(同时允许用户工作)

我使用TPL库执行此操作,对于Android,最接近的近似是Anko Async,但是您也可以使用AsyncTask进行此操作,问题是我向主线程发送了很多消息,因此使用AsyncTask可以完成此操作必须为其发送消息的主线程提供一个处理程序。

在线程中,我循环浏览所有必须下载的图像,然后下载并发送消息到DataFragment,该消息将其发送到当前连接的Activity,该Activity触发适配器中的NotifyItemChanged方法

适配器在创建时会收到Func<int, Bitmap> image_provider,它会调用它并从内存中检索图像

我知道这听起来有些混乱,所以如果您想要代码示例,可以给他们,但是它们在C#中

答案 7 :(得分:0)

在您的应用级gradle中,在存储库下方实施:

implementation 'com.squareup.picasso:picasso:2.5.2'

置于要加载图像的行下方

 Picasso.with(getApplicationContext()).load(config.avatar).into(imageview);

答案 8 :(得分:0)

只需使用Picasso.get()。load(“ http://i.imgur.com/DvpvklR.png”)。into(imageView);要么 Glide.with(getApplicationContext())。load(“ image_url”)。asBitmap()。centerCrop()。into(new BitmapImageViewTarget(imageView)

在适配器中像任何视图一样,无需进行任何额外的操作