RecyclerView notifyItemChanged(position) 使应用程序崩溃并且没有使用 notifyDataSetChanged() 的动画
RecyclerView notifyItemChanged(position) crashes the app and no animations with notifyDataSetChanged()
所以我有一个 RecyclerView,在我拉入其中的每个 xml 中都有一个复选框,当按下该复选框时,该复选框会从 RecyclerView 中删除该特定项目。至少那是我试图做的。据我了解,要使其正常工作,我需要使用 notifyItemChanged(position); (它就在底部)。
但是当我使用 notifyItemChanged(position);如果我按下这些顺序的复选框,它只会删除正确的项目:1、2、3、4、5 或 5、4、3、2、1。如果我尝试删除第一项,它会删除它,但如果我想删除第三项,它会删除第四项。
我发现的另一个选项是使用 notifyDataSetChanged();它可以按任何顺序运行,但是不会显示任何动画。
而且我希望在添加和删除项目时有动画,所以如果有一种方法可以使用 notifyDataSetChanged();我想得到帮助。
public class ListAdapter extends RecyclerView.Adapter{
SharedPreferences sharedpreferences, prefs;
public static final String MyPREFERENCES = "MyPrefs";
public static final String date = "date";
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.nd_table, parent, false);
return new ListViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int adapterPosition) {
//((ListViewHolder) holder).bindView(position);
String data = hwName.get(adapterPosition);
String data2 = hwDesc.get(adapterPosition);
((ListViewHolder) holder).mItemText.setText(data);
((ListViewHolder) holder).mItemText2.setText(data2);
((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
removeItem(adapterPosition);
notifyItemChanged(adapterPosition);
}
});
}
@Override
public int getItemCount() {
return hwName.size();
}
public class ListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mItemText, mItemText2;
public CheckBox buttonDelete;
public ListViewHolder(View itemView) {
super(itemView);
mItemText = (TextView) itemView.findViewById(R.id.pam_name);
mItemText2 = (TextView) itemView.findViewById(R.id.pam_nd);
buttonDelete = (CheckBox) itemView.findViewById(R.id.nd_checkbox);
itemView.setOnClickListener(this);
}
public void bindView(int position) {
String value = hwName.get(position);
String value2 = hwDesc.get(position);
mItemText.setText(value);
mItemText2.setText(value2);
//notifyItemInserted(hwName.size());
}
public void onClick(View view) {
}
}
public void removeItem(int position){
hwName.remove(position);
hwDesc.remove(position);
//notifyDataSetChanged();
notifyItemRemoved(position);
notifyItemChanged(position);
}}
崩溃报告:
FATAL EXCEPTION: main
Process: com.sajev.slush, PID: 14166
java.lang.IndexOutOfBoundsException: Index: 5, Size: 5
at java.util.ArrayList.remove(ArrayList.java:477)
at com.sajev.slush.ListAdapter.removeItem(ListAdapter.java:89)
at com.sajev.slush.ListAdapter.onClick(ListAdapter.java:45)
at android.view.View.performClick(View.java:5646)
at android.widget.CompoundButton.performClick(CompoundButton.java:123)
at android.view.View$PerformClick.run(View.java:22459)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
有两个问题:
调用notifyItemRemoved()
后不要调用notifyItemChanged()
调用 notifyItemRemoved()
将告诉适配器先前在 position
的项目不再存在,这就是您需要做的全部。调用 notifyItemChanged()
告诉适配器 position
处的项目已被修改(也许它的名称已更改,但没有其他改变),因此当您删除项目时它不适合使用。
你遇到了崩溃,因为你按顺序调用了这两个。想象一下,您的列表中只有一项,然后将其删除。当您调用 notifyItemRemoved()
时,适配器现在知道您的列表中有零个项目。但是随后您调用 notifyItemChanged()
,因此适配器尝试获取第一个项目...但是列表为空,所以您崩溃了。
传给onBindViewHolder()
的position
参数不能是final
(有关详细信息,请参阅 ~43:10 的 https://www.youtube.com/watch?v=LqBlYJTfLP4。)
编译器无法阻止您将 final
关键字添加到 onBindViewHolder()
的 position
参数中,但这样做是一个逻辑错误。当您调用 notifyItemRemoved()
或 notifyItemInserted()
等方法时,其他视图持有者是 而不是 re-bound,因此 position
参数将不再反映现实。
不要在点击侦听器中使用 position
参数。相反,在运行时查找它。这是考虑到这两个问题的一些更新代码:
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
...
((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
removeItem(holder.getAdapterPosition());
}
});
}
public void removeItem(int position){
hwName.remove(position);
hwDesc.remove(position);
notifyItemRemoved(position);
}
所以我有一个 RecyclerView,在我拉入其中的每个 xml 中都有一个复选框,当按下该复选框时,该复选框会从 RecyclerView 中删除该特定项目。至少那是我试图做的。据我了解,要使其正常工作,我需要使用 notifyItemChanged(position); (它就在底部)。
但是当我使用 notifyItemChanged(position);如果我按下这些顺序的复选框,它只会删除正确的项目:1、2、3、4、5 或 5、4、3、2、1。如果我尝试删除第一项,它会删除它,但如果我想删除第三项,它会删除第四项。
我发现的另一个选项是使用 notifyDataSetChanged();它可以按任何顺序运行,但是不会显示任何动画。
而且我希望在添加和删除项目时有动画,所以如果有一种方法可以使用 notifyDataSetChanged();我想得到帮助。
public class ListAdapter extends RecyclerView.Adapter{
SharedPreferences sharedpreferences, prefs;
public static final String MyPREFERENCES = "MyPrefs";
public static final String date = "date";
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.nd_table, parent, false);
return new ListViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int adapterPosition) {
//((ListViewHolder) holder).bindView(position);
String data = hwName.get(adapterPosition);
String data2 = hwDesc.get(adapterPosition);
((ListViewHolder) holder).mItemText.setText(data);
((ListViewHolder) holder).mItemText2.setText(data2);
((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
removeItem(adapterPosition);
notifyItemChanged(adapterPosition);
}
});
}
@Override
public int getItemCount() {
return hwName.size();
}
public class ListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mItemText, mItemText2;
public CheckBox buttonDelete;
public ListViewHolder(View itemView) {
super(itemView);
mItemText = (TextView) itemView.findViewById(R.id.pam_name);
mItemText2 = (TextView) itemView.findViewById(R.id.pam_nd);
buttonDelete = (CheckBox) itemView.findViewById(R.id.nd_checkbox);
itemView.setOnClickListener(this);
}
public void bindView(int position) {
String value = hwName.get(position);
String value2 = hwDesc.get(position);
mItemText.setText(value);
mItemText2.setText(value2);
//notifyItemInserted(hwName.size());
}
public void onClick(View view) {
}
}
public void removeItem(int position){
hwName.remove(position);
hwDesc.remove(position);
//notifyDataSetChanged();
notifyItemRemoved(position);
notifyItemChanged(position);
}}
崩溃报告:
FATAL EXCEPTION: main Process: com.sajev.slush, PID: 14166 java.lang.IndexOutOfBoundsException: Index: 5, Size: 5 at java.util.ArrayList.remove(ArrayList.java:477) at com.sajev.slush.ListAdapter.removeItem(ListAdapter.java:89) at com.sajev.slush.ListAdapter.onClick(ListAdapter.java:45) at android.view.View.performClick(View.java:5646) at android.widget.CompoundButton.performClick(CompoundButton.java:123) at android.view.View$PerformClick.run(View.java:22459) at android.os.Handler.handleCallback(Handler.java:761) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:156) at android.app.ActivityThread.main(ActivityThread.java:6523) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
有两个问题:
调用notifyItemRemoved()
后不要调用notifyItemChanged()
调用 notifyItemRemoved()
将告诉适配器先前在 position
的项目不再存在,这就是您需要做的全部。调用 notifyItemChanged()
告诉适配器 position
处的项目已被修改(也许它的名称已更改,但没有其他改变),因此当您删除项目时它不适合使用。
你遇到了崩溃,因为你按顺序调用了这两个。想象一下,您的列表中只有一项,然后将其删除。当您调用 notifyItemRemoved()
时,适配器现在知道您的列表中有零个项目。但是随后您调用 notifyItemChanged()
,因此适配器尝试获取第一个项目...但是列表为空,所以您崩溃了。
传给onBindViewHolder()
的position
参数不能是final
(有关详细信息,请参阅 ~43:10 的 https://www.youtube.com/watch?v=LqBlYJTfLP4。)
编译器无法阻止您将 final
关键字添加到 onBindViewHolder()
的 position
参数中,但这样做是一个逻辑错误。当您调用 notifyItemRemoved()
或 notifyItemInserted()
等方法时,其他视图持有者是 而不是 re-bound,因此 position
参数将不再反映现实。
不要在点击侦听器中使用 position
参数。相反,在运行时查找它。这是考虑到这两个问题的一些更新代码:
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
...
((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
removeItem(holder.getAdapterPosition());
}
});
}
public void removeItem(int position){
hwName.remove(position);
hwDesc.remove(position);
notifyItemRemoved(position);
}