Android 显示错误图像的RecyclerView适配器
我有一个RecyclerView适配器,如下所示:Android 显示错误图像的RecyclerView适配器,android,android-layout,android-xml,android-recyclerview,Android,Android Layout,Android Xml,Android Recyclerview,我有一个RecyclerView适配器,如下所示: public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { private static Context context; private List<Message> mDataset; public RecyclerAdapter(Context context, List&l
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private static Context context;
private List<Message> mDataset;
public RecyclerAdapter(Context context, List<Message> myDataset) {
this.context = context;
this.mDataset = myDataset;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener {
public TextView title;
public LinearLayout placeholder;
public ViewHolder(View view) {
super(view);
view.setOnCreateContextMenuListener(this);
title = (TextView) view.findViewById(R.id.title);
placeholder = (LinearLayout) view.findViewById(R.id.placeholder);
}
}
@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false);
ViewHolder vh = new ViewHolder((LinearLayout) view);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Message item = mDataset.get(position);
holder.title.setText(item.getTitle());
int numImages = item.getImages().size();
if (numImages > 0) {
View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false);
ImageView image = (ImageView) test.findViewById(R.id.image);
Glide.with(context)
.load("http://www.website.com/test.png")
.fitCenter()
.into(image);
holder.placeholder.addView(test);
}
}
@Override
public int getItemCount() {
return mDataset.size();
}
}
公共类RecyclerAdapter扩展了RecyclerView.Adapter{
私有静态语境;
私有列表数据集;
公共RecyclerAdapter(上下文,列表myDataset){
this.context=上下文;
this.mDataset=myDataset;
}
公共静态类ViewHolder扩展了RecyclerView.ViewHolder实现了View.OnCreateContextMenuListener、View.OnClickListener{
公共文本视图标题;
公共线路布局占位符;
公共视图持有者(视图){
超级(视图);
view.setOnCreateContextMenuListener(此);
title=(TextView)view.findViewById(R.id.title);
占位符=(LinearLayout)view.findViewById(R.id.placeholder);
}
}
@凌驾
public RecyclerAdapter.ViewHolder onCreateViewHolder(视图组父级,int-viewType){
View=LayoutFlater.from(parent.getContext()).flate(R.layout.message\u布局,parent,false);
ViewHolder vh=新的ViewHolder((线性布局)视图);
返回vh;
}
@凌驾
公共无效onBindViewHolder(ViewHolder,int位置){
消息项=mDataset.get(位置);
holder.title.setText(item.getTitle());
int numImages=item.getImages().size();
如果(数字图像>0){
View test=LayoutInflater.from(holder.placeholder.getContext()).flate(R.layout.images,holder.placeholder,false);
ImageView image=(ImageView)test.findViewById(R.id.image);
带(上下文)滑动
.加载(“http://www.website.com/test.png")
.fitCenter()
.进入(图像);
holder.placeholder.addView(测试);
}
}
@凌驾
public int getItemCount(){
返回mDataset.size();
}
}
然而,RecyclerView中的一些项目在不应该显示的情况下显示图像。我怎样才能阻止这种事情发生
我在
onBindViewHolder()中执行检查if(numImages>0){
,但这仍然不能阻止它显示不应该有图像的项目的图像。这里的问题是,当您使用将被回收的视图时,您需要在绑定视图时处理所有可能的场景
例如,如果要将ImageView添加到数据源位置0上的LinearLayout,则如果位置4不符合条件,则其视图很可能在绑定位置0时添加ImageView
您可以将R.layout.images内容添加到
R.layout.message\u layout版面的R.id.placeholder并根据具体情况显示/隐藏占位符
因此,您的onBindViewHolder方法类似于:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Message item = mDataset.get(position);
holder.title.setText(item.getTitle());
int numImages = item.getImages().size();
if (numImages > 0) {
holder.placeholder.setVisivility(View.VISIBLE);
ImageView image = (ImageView)holder.placeholder.findViewById(R.id.image);
Glide.with(context)
.load("http://www.website.com/test.png")
.fitCenter()
.into(image);
}else{
holder.placeholder.setVisibility(View.INVISIBLE);
}
}
您应该设置
imageView.setImageDrawable(null)
在使用glide设置图像之前,请在onBindViewHolder()
中
将image drawable设置为null可修复此问题
希望有帮助!问题出在onBindViewHolder中,这里:
if (numImages > 0) {
View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false);
ImageView image = (ImageView) test.findViewById(R.id.image);
Glide.with(context)
.load("http://www.website.com/test.png")
.fitCenter()
.into(image);
holder.placeholder.addView(test);
}
如果numImages等于0,则您只是允许以前开始的加载继续加载到要重用的视图中。加载完成后,它仍会将旧图像加载到您的视图中。为防止出现这种情况,请通过调用clear告诉Glide取消以前的加载:
if (numImages > 0) {
View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false);
ImageView image = (ImageView) test.findViewById(R.id.image);
Glide.with(context)
.load("http://www.website.com/test.png")
.fitCenter()
.into(image);
holder.placeholder.addView(test);
} else {
Glide.clear(image);
}
调用into()
时,Glide会为您取消旧加载。如果您不打算调用into()
,则必须自己调用clear()
对onBindViewHolder的每次调用都必须包括一个
load()
调用或clear()
调用。我还遇到了RecyclerView显示错误图像的问题。这是因为RecyclerView没有为每个新列表项扩展视图:相反,列表项正在被回收
通过循环使用视图,我们可以轻松理解克隆视图。克隆的视图可能具有来自上一次交互的图像集
如果您使用毕加索、Glide或其他库进行异步加载,这一点尤其公平。这些库保存对ImageView的引用,并在加载图像时在该引用上设置图像
加载图像时,项目视图可能已被克隆,并且图像将被设置为错误的克隆
长话短说,我通过限制RecyclerView克隆我的项目视图解决了这个问题:
在ViewHolder构造函数中设置可循环(false)
现在RecyclerView的工作速度慢了一点,但至少图像设置正确
或者可以选择将图像加载到ViewRecycled上(ViewHolder holde)我也遇到了同样的问题,我这样修复了它:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private static Context context;
private List<Message> mDataset;
public RecyclerAdapter(Context context, List<Message> myDataset) {
this.context = context;
this.mDataset = myDataset;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener {
public TextView title;
public LinearLayout placeholder;
public ViewHolder(View view) {
super(view);
view.setOnCreateContextMenuListener(this);
title = (TextView) view.findViewById(R.id.title);
placeholder = (LinearLayout) view.findViewById(R.id.placeholder);
}
}
@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false);
ViewHolder vh = new ViewHolder((LinearLayout) view);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Message item = mDataset.get(position);
holder.title.setText(item.getTitle());
int numImages = item.getImages().size();
if (numImages > 0) {
View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false);
ImageView image = (ImageView) test.findViewById(R.id.image);
Glide.with(context)
.load("http://www.website.com/test.png")
.fitCenter()
.into(image);
holder.placeholder.addView(test);
}
}
@Override
public int getItemCount() {
return mDataset.size();
}
}
目标:打开视图附加到Windows
@Override
public void onViewAttachedToWindow(Holder holder) {
super.onViewAttachedToWindow(holder);
StructAllItems sfi = mArrayList.get(position);
if (!sfi.getPicHayatParking().isEmpty()) {
holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicHayatParking() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop));
}
if (!sfi.getPicSleepRoom().isEmpty()) {
holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSleepRoom() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop));
}
if (!sfi.getPicSalonPazirayi().isEmpty()) {
holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSalonPazirayi() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop));
}
if (!sfi.getPicNamayeStruct().isEmpty()) {
holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicNamayeStruct() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop));
}
}
我也有同样的问题,并以下面的解决方案结束,它对我来说很好 掌握这个解决方案可能也适合您(将下面的代码放在适配器类中)—— 如果您正在使用Kotlin-
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
如果您使用的是JAVA-
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
这在onBindViewHolder中对我有效
if(!m.getPicture().isEmpty())
{
holder.setIsRecyclable(false);
Picasso.with(holder.profile_pic.getContext()).load(m.getPicture()).placeholder(R.mipmap.ic_launcher_round).into(holder.profile_pic);
Animation fadeOut = new AlphaAnimation(0, 1);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(1000);
holder.profile_pic.startAnimation(fadeOut);
}
else
{
holder.setIsRecyclable(true);
}
我从照片库中获取图片并将其放入GridLayoutManager的recyclerview时遇到了类似的问题(Glide从未遇到过问题)。因此在BindViewHolder适配器中,使用HashMap或SparseIntArray来放置当前的哈希代码(这是回收视图的共同点)然后调用后台任务,在设置映像之前,检查hashcode键(始终将当前适配器位置作为值)是否与第一次调用后台任务时的值(适配器位置)相同
(Global variable)
private SparseIntArray hashMap = new SparseIntArray();
onBindViewHolder(ViewHolder holder, int position){
holder.imageView.setImageResource(R.drawable.grey_square);
hashMap.put(holder.hashCode(), position);
yourBackgroundTask(ViewHolder holder, int position);
}
yourBackGroundTask(ViewHolder holder, int holderPosition){
do some stuff in the background.....
*if you want to stop to image from downloading / or in my case
fetching the image from MediaStore then do -
if(hashMap.get(holder.hashCode())!=(holderPos)){
return null;
}
- in the background task, before the call to get the
image
onPostExecute{
if(hashMap.get(holder.hashCode())==(holderPosition)){
holder.imageView.setImageBitmap(result);
}
}
}
有时在使用RecyclerView时,视图可能会被重新使用,并保留以前位置t的大小
@Override
public void onBindViewHolder(@NonNull RecylerViewHolder holder, int position) {
NewsFeed currentFeed = newsFeeds.get(position);
holder.textView.setText(currentFeed.getNewsTitle());
holder.sectionView.setText(currentFeed.getNewsSection());
if(currentFeed.getImageId() == "NOIMG") {
holder.setIsRecyclable(false);
Log.v("ImageLoad","Image not loaded");
} else {
Picasso.get().load(currentFeed.getImageId()).into(holder.imageView);
Log.v("ImageLoad","Image id "+ currentFeed.getImageId());
}
holder.dateView.setText(getModifiedDate(currentFeed.getDate()));
}