所以一段时间以来,我一直在努力用最佳方法在Android的ListView中加载图像。
图像来自服务器,因此可能需要一些时间来加载。据我了解,只有两种方法可以实现此目的:
1-在主线程上加载图像-这会导致视图显示和滚动时立即显示正确的图像,但滚动性能较差,并可能导致应用挂起和崩溃。
2-将图像加载到AsyncTask中。这意味着列表显示或滚动时图像将为空白,但最终显示。由于列表完成了缓存,因此您还可以获得错误的图像。但这可以提供良好的性能和滚动效果,并且不会挂起/崩溃。
似乎两种解决方案均无法正常工作。必须有一个可行的解决方案??我看过其他这样的帖子,但答案似乎总是1或2,但都不是一个好的解决方案...
我的列表适配器代码如下。 HttpGetImageAction.fetchImage()方法要么执行异步任务,要么根据我设置的标志在主线程上获取图像。加载完图像后,我还会在本地和磁盘上缓存图像,因此问题主要发生在第一次(但是缓存仅用于100张图像,并且列表有1000s)
ConcurrentModificationException
答案 0 :(得分:4)
切勿在主线程上加载图像。任何网络调用都应异步进行,并且不应在主线程上进行。您的图像可能会快速加载(在主线程上),因为您可能具有良好的Internet连接,图像较小和/或图像较少。但是,想象一下,如果使用您的应用程序的人的互联网速度较慢,然后有一天您的列表增加到数百个,会发生什么!
下面的方法是加载滚动视图内容的公认方法
使用像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并下载并将其保存在缓存中,这样,每当您再次打开同一映像时,它将加载得更快,并且会阻止网络的使用
答案 5 :(得分:0)
您可以尝试非常快速且经过优化的UnivarsalImageLoader。 它支持多线程图像加载(异步或同步)和高级别的自定义。
答案 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)
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)
在适配器中像任何视图一样,无需进行任何额外的操作