我正在尝试使用RecyclerView构建一个简单的列表,这将允许我添加/删除项目。
我可以删除这些项目,但是删除某个项目后,似乎未在“重新计算”职位。
例如,列表中有20个项目,如果我删除最后一个项目,则位置为19(应有的位置)。该项目将从列表中删除,但是当我再次单击以删除最后一个项目时,位置仍为19,应该为18:
D/RecycleViewTest: Remove at Position: 19
D/RecycleViewTest: Remove at Position: 19
这将导致以下异常:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.recycleviewtest, PID: 1763
java.lang.IndexOutOfBoundsException: Index: 19, Size: 19
at java.util.ArrayList.remove(ArrayList.java:477)
at com.example.recycleviewtest.MainActivity$1.onRemoveClick(MainActivity.java:45)
at com.example.recycleviewtest.SimpleViewHolder$2.onClick(SimpleViewHolder.java:42)
at android.view.View.performClick(View.java:6205)
at android.view.View$PerformClick.run(View.java:23653)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
我将通过以下方式移除这些物品:
itemList.remove( position );
adapter.notifyItemRemoved( position );
我是否需要对某种函数进行额外的调用,以便列表得到“重新计算”?
这是MainActivity:
public class MainActivity extends AppCompatActivity
{
List<SimpleViewModel> itemList;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
itemList = generateSimpleList();
final SimpleAdapter adapter = new SimpleAdapter(itemList);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.simple_recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator( new DefaultItemAnimator() );
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new SimpleAdapter.onItemClickListener() {
@Override
public void onItemClick(int position)
{
Log.d( "RecycleViewTest", "Click at Position: " + position );
adapter.notifyItemChanged( position );
}
@Override
public void onRemoveClick( int position )
{
Log.d( "RecycleViewTest", "Remove at Position: " + position );
itemList.remove( position );
adapter.notifyItemRemoved( position );
}
});
}
private List<SimpleViewModel> generateSimpleList()
{
List<SimpleViewModel> simpleViewModelList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
simpleViewModelList.add(new SimpleViewModel(String.format(Locale.US, "This is item %d", i)));
}
return simpleViewModelList;
}
}
这是我的RecyclerView.Adapter(SimpleAdapter):
public class SimpleAdapter extends RecyclerView.Adapter {
private List<SimpleViewModel> models = new ArrayList<>();
private onItemClickListener mListener;
public SimpleAdapter(final List<SimpleViewModel> viewModels)
{
if (viewModels != null) {
this.models.addAll(viewModels);
}
}
public void setOnItemClickListener( onItemClickListener listener )
{
mListener = listener;
}
public interface onItemClickListener
{
void onItemClick( int position );
void onRemoveClick( int position);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new SimpleViewHolder(view, mListener);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
((SimpleViewHolder) holder).bindData(models.get(position));
}
@Override
public int getItemCount() {
return models.size();
}
@Override
public int getItemViewType(final int position) {
return R.layout.item;
}
}
这是我的RecyclerView.ViewHolder(SimpleViewHolder):
public class SimpleViewHolder extends RecyclerView.ViewHolder {
private TextView simpleTextView;
private ImageView imgRemove;
public SimpleViewHolder(final View itemView, final SimpleAdapter.onItemClickListener listener) {
super(itemView);
simpleTextView = (TextView) itemView.findViewById(R.id.simple_text);
imgRemove = (ImageView) itemView.findViewById(R.id.imgRemove);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if( listener != null )
{
int position = getAdapterPosition();
if( position != RecyclerView.NO_POSITION )
{
listener.onItemClick( position );
}
}
}
});
imgRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if( listener != null )
{
int position = getAdapterPosition();
if( position != RecyclerView.NO_POSITION )
{
listener.onRemoveClick( position );
}
}
}
});
}
public void bindData(final SimpleViewModel viewModel) {
simpleTextView.setText(viewModel.getSimpleText() );
}
}
任何提示都说明我在哪里出错了?谢谢!
更新:
我刚刚意识到,即使要播放的动画“播放过”,也没有删除任何实际项目,它们只是“重新出现”。
答案 0 :(得分:2)
问题出在适配器的构造函数中:
private List<SimpleViewModel> models = new ArrayList<>(); private onItemClickListener mListener; public SimpleAdapter(final List<SimpleViewModel> viewModels) { if (viewModels != null) { this.models.addAll(viewModels); } }
适配器不保留您传递给此构造方法的列表。而是将列表的内容复制到适配器自己的单独且不同的列表中。
这意味着以后,当您执行
@Override public void onRemoveClick( int position ) { Log.d( "RecycleViewTest", "Remove at Position: " + position ); itemList.remove( position ); adapter.notifyItemRemoved( position ); }
该项目已从itemList
中删除,但没有从适配器列表中删除。
您必须从适配器的复制列表中删除该项目,或者必须更改适配器以使其与活动共享相同的列表。可能最简单的事情是更换适配器:
private List<SimpleViewModel> models = new ArrayList<>();
private onItemClickListener mListener;
public SimpleAdapter(final List<SimpleViewModel> viewModels)
{
if (viewModels != null) {
this.models = viewModels; // instead of copying the contents
}
}
答案 1 :(得分:0)
在删除项目后使用此 mRecyclerView.getRecycledViewPool()。clear(); mAdapter.notifyDataSetChanged();
答案 2 :(得分:0)
深入研究之后,似乎其他人一直在使用名为notifyItemRangeChanged
的其他方法,这听起来像发生了什么事。因此,在完成itemList.remove(position);
之后
尝试也做
adapter.notifyItemRemoved( position );
adapter.notifyItemRangeChanged(position, itemList.size());
答案 3 :(得分:0)
getAdapterPosition()
返回1 - n
的范围位置,并且您的列表具有0 - n
的范围位置。
请尝试
itemList.remove( position - 1 ); //to normalize
adapter.notifyItemRemoved( position );