所以,我只是代码
override fun onBindViewHolder(
holder: ViewHolder,
position: Int
) {
DownloadImageTask(holder.avatar).execute(mDataSet[position].avatar);
holder.header.setText(mDataSet[position].header)
holder.body.setText(mDataSet[position].body)
for (i in 0 until mDataSet[position].images.size){
val imgUrl= mDataSet[position].images.get(i)
var image= ImageView(holder.itemView.context)
image.layoutParams = ViewGroup.LayoutParams(200, 200)
image.maxHeight = 200
image.maxWidth = 200
val layout= holder.itemView.findViewById<View>(R.id.linear_layout)
DownloadImageTask(image).execute(imgUrl)
layout.linear_layout.addView(image)
}
}
但是在视图中向下和向上滚动后,图像会在回收器视图中的任何项目之间随机播放。那么,如何解决它呢?
也不要忘记删除以前添加到linear_layout
的图像视图。 尝试在取消下载过程后添加linear_layout.removeAllViews()
,然后在开始新图像下载之前。
编辑:如果您更新为使用Glide..您的代码必须小于此:
override fun onBindViewHolder(
holder: ViewHolder,
position: Int
) {
Glide.with(holder.avatar.context)
.load(mDataSet[position].avatar)
.into(holder.avatar);
holder.header.setText(mDataSet[position].header)
holder.body.setText(mDataSet[position].body)
val layout= holder.itemView.findViewById<View>(R.id.linear_layout)
//cancel previous image download
layout.linear_layout.children.toList().filter { it is ImageView }
.forEach { Glide.with(holder.itemView.context).clear(it) }
// remove image views
layout.linear_layout.removeAllViews()
//add row images
for (i in 0 until mDataSet[position].images.size){
val imgUrl= mDataSet[position].images.get(i)
var image= ImageView(holder.itemView.context)
image.layoutParams = ViewGroup.LayoutParams(200, 200)
image.maxHeight = 200
image.maxWidth = 200
Glide.with(holder.itemView.context).load(imgUrl).into(image)
layout.linear_layout.addView(image)
}
}
注意:我尝试保留代码示例,但最好重用现有的动态图像视图并删除其余部分。
发生这种情况是因为相同的视图被重用,并且当视图快速滚动时,您在单个视图上有多个异步任务。如前面的答案库所述,如壁画,滑翔,凌空等会自动处理它。
在当前方案中解决此问题的最简单方法是将异步任务设置为视图中的标记,并在重用同一视图时取消在其上设置的先前异步任务。(请原谅java语法,我对Kotlin还不友好(
像这样:
AsyncTask prevTask = (AsyncTask) holder.avatar.getTag();
if(prevTask != null) {
prevTask.cancel();
}
AsyncTask task = DownloadImageTask(holder.avatar);
task.execute(mDataSet[position].avatar)
holder.avatar.setTag(task);
您必须为 for 循环中的图像编写类似的代码。
看起来您正在使用AsyncTask
这似乎是罪魁祸首。 当您将以前创建的ViewHolders
滚动到屏幕上时,RecyclerView
会重新绑定它们,并且由于您似乎没有取消未完成的异步任务,因此您有一个争用案例。
可能是异步任务在重新绑定ViewHolder
后完成,因此它会使用mDataSet
中旧项目的图像更新ViewHolder
。要解决此问题,您需要跟踪并取消异步任务,因为ViewHolders
是绑定/取消绑定的。
更好的是,我建议使用像Glide
这样的图像加载库。绑定ViewHolder
后,您可以使用Glide.clear()
取消之前对ImageViews
的任何加载请求,并使用Glide.load(...).into(...)
加载新图像。