未从 RecyclerView 正确删除的项目

Posted

技术标签:

【中文标题】未从 RecyclerView 正确删除的项目【英文标题】:Items not removed properly from RecyclerView 【发布时间】:2017-12-15 05:03:05 【问题描述】:

我正在使用 AppWidgetHostViews 填充 RecyclerView。它们按顺序排列在另一个下方,每个旁边都有删除按钮。这就是我设置 RecyclerView 和 Adapter 的方式(event.object 是 AppWidgetHostView):

        private List<View> viewList = new ArrayList<>();

        mAdapter = new AppWidgetAdapter(this);
        mRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
        mRecycler.setItemAnimator(new DefaultItemAnimator());
        mRecycler.setAdapter(mAdapter);
        viewList.add((View) event.eventObject);
        mAdapter.setData(viewList);

这是我持有 AppWidgetHostViews 的适配器:

public class AppWidgetAdapter extends RecyclerView.Adapter<AppWidgetAdapter.AppWidgetHolder> 

private List<View> viewList = new ArrayList<>();
private AdapterListener listener;

public AppWidgetAdapter(AdapterListener listener) 
    this.listener = listener;


public void setData(List<View> list) 
    viewList.clear();
    viewList.addAll(list);
    notifyDataSetChanged();


@Override
public AppWidgetHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.app_widget_layout, parent, false);
    return new AppWidgetHolder(view);


@Override
public void onBindViewHolder(final AppWidgetHolder holder, int position) 
    final View view = getItem(position);
    holder.setView(view);
    holder.setNum(String.valueOf(position));

    holder.button.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            int pos = holder.getAdapterPosition();
            viewList.remove(pos);
            notifyItemRemoved(pos);
            notifyItemRangeRemoved(pos, viewList.size());
            listener.onItemRemoved(pos);
        
    );


private View getItem(int position) 
    return !viewList.isEmpty() ? viewList.get(position) : null;


@Override
public int getItemCount() 
    return viewList.size();


class AppWidgetHolder extends RecyclerView.ViewHolder 

    private FrameLayout view;
    private Button button;

    AppWidgetHolder(View itemView) 
        super(itemView);
        view = (FrameLayout) itemView.findViewById(R.id.app_widget);
        button = (Button) itemView.findViewById(R.id.delete);

    

    private void setView (View view) 
        if(view.getParent() != null) 
            ((ViewGroup)view.getParent()).removeView(view);
        
        this.view.addView(view);
    

    private void setNum (String num) 
        this.button.setText(num);
    


我的 ViewHolder 的 XML 如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_
android:layout_
android:orientation="vertical"
android:layout_marginBottom="20dp">

<Button
    android:layout_centerInParent="true"
    android:id="@+id/delete"
    android:layout_
    android:layout_alignParentEnd="true"
    android:layout_
    android:layout_marginLeft="5dp"
    tools:text="Del" />

<FrameLayout
    android:layout_toStartOf="@id/delete"
    android:layout_centerHorizontal="true"
    android:layout_centerInParent="true"
    android:id="@+id/app_widget"
    android:layout_
    android:layout_
    android:layout_alignParentStart="true" />

所以在 onBindViewHolder 方法中,我设置了 onClick 监听器,它应该删除该位置的 AppWidgetHostView。所以在通知项目删除后,我调用 listener.onItemRemoved(pos),它在片段中的实现如下所示:

   @Override
public void onItemRemoved(int position) 
    viewList.remove(position);
    mAdapter.setData(viewList);
 

所以它再次为适配器设置数据并通知数据集已更改。

但问题是,当我单击删除按钮时,项目没有被正确删除。 ViewList 可以调整大小,但是项目的行为很奇怪,例如,如果我添加 3 个项目并删除第二个项目,它会留在屏幕上,但第三个会在它上面(第二个仍然可见),然后,如果我删除第一个,它会保留,以前的第二个现在被删除,新的第二个在第一个之上。但是,如果我为每个项目单击删除按钮,它将删除所有视图,但在该过程中它们的行为会很奇怪......有什么建议,提示吗?

【问题讨论】:

您正在删除onClick() 中的项目,然后在onItemRemoved() 中再次删除它。在onClick() 中删除对onItemRemoved() 的调用。 首先我在适配器中删除它,然后我调用 onItemRemoved,以删除我在 setData 方法中传递给适配器的片段视图列表中的项目。例如,如果我删除适配器中的项目并且不调用片段中的删除然后我添加新项目,它会将带有已删除项目的列表传递回适配器。 不需要这样做。两个列表将具有相同的引用。See this。 所以我应该在 onClick 方法中调用 onItemRemoved() 吗?然后在它的实现中删除该位置的视图列表中的项目并调用 adapter.notifyItemRemoved 和 notifyItemRangeRemoved? 【参考方案1】:

尝试只在 onBindViewHolder 中添加后续代码:

holder.button.setOnClickListener(new View.OnClickListener() 
    @Override
    public void onClick(View v) 
        viewList.remove(position);
        notifyItemRemoved(position);
        //notifyDataSetChanged();
    
);

【讨论】:

不幸的是没有帮助:/我读过你应该总是在从列表中删除它之后使用 notifyItemRemoved 并在之后使用 notifyItemRangeRemoved .. 但是每次,如果我有 3 个项目并删除第二个,它停留在屏幕上,适配器更新,但是第三个项目上升并覆盖了仍然可见的前第二个项目......【参考方案2】:

使用@Adithya 和@Stanislav Bondar 的建议,我想出了解决方案:

这是 onBindViewHolder 方法:

  @Override
public void onBindViewHolder(final AppWidgetHolder holder, final int position) 
    final View view = getItem(position);
    holder.setView(view);
    holder.setNum(String.valueOf(position));

    holder.button.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 

            int pos = holder.getAdapterPosition();
            viewList.remove(pos);
            listener.onItemRemoved(pos);
        
    );

在 onItemRemoved 里面:

@Override
public void onItemRemoved(int position) 
    viewList.remove(position);
    mAdapter.notifyItemRemoved(position);

我必须删除适配器和片段内该位置的项目,因为如果我在片段中有 5 个项目我传递给适配器并且如果我只在适配器中删除它,一旦我再次传递新项目,它将发送6 项而不是 5 .. 也许有更好的方法,但这确实解决了问题

【讨论】:

我很难理解为什么onBindViewHolder 中的final int positionholder.getAdapterPosition(); 不同。当我使用final int position 时,项目以错误的方式被删除。 holder.getAdapterPosition(); 总是获得正确的项目位置。【参考方案3】:

删除项目时您不必致电setData(List&lt;View&gt; list)。你打了两次viewList.remove(pos);,第一次是onBindViewHolder,第二次是onItemRemoved(int position)

【讨论】:

首先我在适配器中删除它,然后我调用 onItemRemoved,以删除我在 setData 方法中传递给适配器的片段视图列表中的项目。例如,如果我删除适配器中的项目并且不调用片段中的删除然后我添加新项目,它会将带有已删除项目的列表传递回适配器。 @joe 删除项目时您不需要清除 viewList。使用mAdapter.notifyItemRemoved(pos); 而不是mAdapter.setData(viewList); 所以我可以从 onClick() 调用 onItemRemoved(int position) 并在它的实现中调用 mAdapter.notifyItemRemoved(pos); 吗?或者我也应该调用 viewList.remove(position);在 onClick() 中?

以上是关于未从 RecyclerView 正确删除的项目的主要内容,如果未能解决你的问题,请参考以下文章

SSZiparchive 未从项目中删除

InstallShield 2011 未从服务列表中删除服务

如何正确突出显示 RecyclerView 上的选定项目?

RecyclerView 上的项目删除没有动画

RecyclerView 项目点击监听器的正确方式

如何修复 Recyclerview 项目删除显示错误