从 Recyclerview 中删除项目时应用程序崩溃
App crashes while deleting an item from Recyclerview
在我的应用程序中,我在回收站视图中显示了项目列表。我为 recyclerview 中的每个项目创建了两个功能编辑和删除。使用此应用程序,用户可以创建任务列表,可以编辑项目,也可以从回收站视图中删除项目。现在,如果我单击编辑,它会完美运行。但是,如果我单击删除选项,应用程序会崩溃,并在适配器 class.
中显示消息数组索引超出 rance 异常
这是我的适配器代码。我还在代码中提到了应用程序崩溃的那一行。
已编辑适配器 Class
public class TodoAdapter extends RealmRecyclerViewAdapter<TodoModel, TodoAdapter.TaskHolder> {
public final static String INTENT_KEY_ID = "taskId";
public final static String INTENT_KEY_POSITION = "position";
public final static String DATE_FORMAT = "dd/MMM/yy";
private Realm realm;
public interface TaskListener {
}
private final TaskListener taskListener;
private final Context context;
public TodoAdapter(TaskListener taskListener, RealmResults<TodoModel> realmResults, Context context, Realm realm) {
super(realmResults, true);
this.taskListener = taskListener;
this.context = context;
this.realm = realm;
}
@Override
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new TaskHolder( LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_row, parent, false));
}
@Override
public void onBindViewHolder(TaskHolder holder, final int position) {
final TodoModel task = getData().get(position);
holder.taskTextView.setText(task.getName());
holder.doneCheckBox.setChecked(task.isDone());
holder.timeTextView.setText( task.getTime() );
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
final Date date = (task.getDate());
if (sdf.format(date).equals(sdf.format(getDate(0))))
holder.dateTextView.setText("Today");
else if (sdf.format(date).equals(sdf.format(getDate(-1))))
holder.dateTextView.setText("Yesterday");
else if (sdf.format(date).equals(sdf.format(getDate(1))))
holder.dateTextView.setText("Tomorrow");
else if (date.getTime() < getDate(6).getTime()) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
holder.dateTextView.setText( DateFormat.format("EEEE", calendar.getTime()).toString());
} else
holder.dateTextView.setText(sdf.format(task.getDate()));
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(context, TodoAddActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(INTENT_KEY_ID, getTask(position).getId());
context.startActivity(intent);
}
});
holder.doneCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TodoModel task = new TodoModel();
task.setId(getTask(position).getId());
task.setDate(getTask(position).getDate());
task.setName(getTask(position).getName());
task.setDone(((CheckBox) v).isChecked());
updateTask(position, task);
}
});
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) {
removeTask(position);
notifyDataSetChanged();
return;
}
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
});
}
public class TaskHolder extends RecyclerView.ViewHolder {
public CardView cardView;
public TextView taskTextView;
public TextView dateTextView;
public TextView timeTextView;
public ImageView deleteImageView;
public CheckBox doneCheckBox;
public TaskHolder(View itemView) {
super(itemView);
taskTextView = (TextView) itemView.findViewById( R.id.row_task_list_tv_name);
dateTextView = (TextView) itemView.findViewById(R.id.row_task_list_tv_date);
timeTextView=(TextView)itemView.findViewById( R.id.row_task_list_tv_time );
deleteImageView = (ImageView) itemView.findViewById(R.id.row_task_list_iv_delete);
doneCheckBox = (CheckBox) itemView.findViewById(R.id.row_task_list_cb_done);
cardView = (CardView) itemView.findViewById(R.id.cardView);
}
}
private Date getDate(int day) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, day);
return calendar.getTime();
}
protected TodoModel getTask(int position) {
return getData().get(position);
}
protected void updateTask(int position, TodoModel task) {
realm.beginTransaction();
TodoModel newTask = realm.where(TodoModel.class).equalTo("id", task.getId()).findFirst();
newTask.setDate(task.getDate());
newTask.setDone(task.isDone());
newTask.setName(task.getName());
realm.commitTransaction();
}
protected void removeTask(int position) {
TodoModel newTask = realm.where(TodoModel.class).equalTo("id", getTask(position).getId()).findFirst();
realm.beginTransaction();
newTask.deleteFromRealm();
realm.commitTransaction();
notifyItemRemoved(position);
}
}
崩溃报告
09-10 12:25:57.876 7332-7332/realmtest.com.to_do_list_test E/AndroidRuntime: FATAL EXCEPTION: main
Process: realmtest.com.to_do_list_test, PID: 7332
java.lang.ArrayIndexOutOfBoundsException: Out of range in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 133(requested: 1 valid: 1)
at io.realm.internal.Collection.nativeGetRow(Native Method)
at io.realm.internal.Collection.getUncheckedRow(Collection.java:386)
at io.realm.OrderedRealmCollectionImpl.get(OrderedRealmCollectionImpl.java:106)
at io.realm.RealmResults.get(RealmResults.java:53)
at io.realm.OrderedRealmCollectionImpl.get(OrderedRealmCollectionImpl.java:19)
at realmtest.com.to_do_list_test.activity.TodoAdapter.getTask(TodoAdapter.java:157)
at realmtest.com.to_do_list_test.activity.TodoAdapter.onClick(TodoAdapter.java:106)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
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:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
getData() 的实现
@Nullable
public OrderedRealmCollection<T> getData() {
return adapterData;
}
任务活动Class
public class TaskActivity extends AppCompatActivity implements TodoAdapter.TaskListener{
private static final int ADD_TASK_REQUEST_CODE = 1000;
private static final int EDIT_TASK_REQUEST_CODE = 1001;
private Realm realm;
private RecyclerView recyclerView;
private TodoAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_todo_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("ToDo List");
setSupportActionBar(toolbar);
realm = Realm.getDefaultInstance();
recyclerView =(RecyclerView)findViewById(R.id.activity_tasks_ll_task);
setUpRecycler();
// Variables
// Views
FloatingActionButton addFloatingActionButton = (FloatingActionButton) findViewById(R.id.activity_tasks_fab_add);
//Listeners
addFloatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(new Intent(getApplicationContext(), TodoAddActivity.class), ADD_TASK_REQUEST_CODE);
}
});
}
private void setAdapter() {
adapter = new TodoAdapter(this, realm.where(TodoModel.class).findAll(),this,realm);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void setUpRecycler() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
// use a linear layout manager since the cards are vertically scrollable
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
setAdapter();
}
}
image1
image2
您在删除条目后更改了适配器列表,但没有通知适配器您更改了列表的大小。因此,您必须告诉适配器列表的大小已更改。
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) { //Error for this line
removeTask(position);
notifyDataSetChanged(); <-------------------Add this line to your code.
return;
}
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
});
无论何时更改适配器列表的大小时,都必须通过调用函数 notifyDataSetChanged().[= 显式告知适配器有关更改的信息11=]
从 if (getTask(position).isDone()) {
中删除 return 语句并将 AlertDialog
放在 if 的 else 子句中,如下所示。
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) {
removeTask(position);
notifyDataSetChanged();
}else {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
}
});
notifyDataSetChanged()
可以用
但是如果您想显示动画以及更新列表中的项目位置
在sequest中使用此代码
notifyItemRemoved(position)
MH: 用于删除项目并显示动画
notifyItemRangeChanged(position, ListSize);
在我的应用程序中,我在回收站视图中显示了项目列表。我为 recyclerview 中的每个项目创建了两个功能编辑和删除。使用此应用程序,用户可以创建任务列表,可以编辑项目,也可以从回收站视图中删除项目。现在,如果我单击编辑,它会完美运行。但是,如果我单击删除选项,应用程序会崩溃,并在适配器 class.
中显示消息数组索引超出 rance 异常这是我的适配器代码。我还在代码中提到了应用程序崩溃的那一行。
已编辑适配器 Class
public class TodoAdapter extends RealmRecyclerViewAdapter<TodoModel, TodoAdapter.TaskHolder> {
public final static String INTENT_KEY_ID = "taskId";
public final static String INTENT_KEY_POSITION = "position";
public final static String DATE_FORMAT = "dd/MMM/yy";
private Realm realm;
public interface TaskListener {
}
private final TaskListener taskListener;
private final Context context;
public TodoAdapter(TaskListener taskListener, RealmResults<TodoModel> realmResults, Context context, Realm realm) {
super(realmResults, true);
this.taskListener = taskListener;
this.context = context;
this.realm = realm;
}
@Override
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new TaskHolder( LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_row, parent, false));
}
@Override
public void onBindViewHolder(TaskHolder holder, final int position) {
final TodoModel task = getData().get(position);
holder.taskTextView.setText(task.getName());
holder.doneCheckBox.setChecked(task.isDone());
holder.timeTextView.setText( task.getTime() );
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
final Date date = (task.getDate());
if (sdf.format(date).equals(sdf.format(getDate(0))))
holder.dateTextView.setText("Today");
else if (sdf.format(date).equals(sdf.format(getDate(-1))))
holder.dateTextView.setText("Yesterday");
else if (sdf.format(date).equals(sdf.format(getDate(1))))
holder.dateTextView.setText("Tomorrow");
else if (date.getTime() < getDate(6).getTime()) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
holder.dateTextView.setText( DateFormat.format("EEEE", calendar.getTime()).toString());
} else
holder.dateTextView.setText(sdf.format(task.getDate()));
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(context, TodoAddActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(INTENT_KEY_ID, getTask(position).getId());
context.startActivity(intent);
}
});
holder.doneCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TodoModel task = new TodoModel();
task.setId(getTask(position).getId());
task.setDate(getTask(position).getDate());
task.setName(getTask(position).getName());
task.setDone(((CheckBox) v).isChecked());
updateTask(position, task);
}
});
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) {
removeTask(position);
notifyDataSetChanged();
return;
}
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
});
}
public class TaskHolder extends RecyclerView.ViewHolder {
public CardView cardView;
public TextView taskTextView;
public TextView dateTextView;
public TextView timeTextView;
public ImageView deleteImageView;
public CheckBox doneCheckBox;
public TaskHolder(View itemView) {
super(itemView);
taskTextView = (TextView) itemView.findViewById( R.id.row_task_list_tv_name);
dateTextView = (TextView) itemView.findViewById(R.id.row_task_list_tv_date);
timeTextView=(TextView)itemView.findViewById( R.id.row_task_list_tv_time );
deleteImageView = (ImageView) itemView.findViewById(R.id.row_task_list_iv_delete);
doneCheckBox = (CheckBox) itemView.findViewById(R.id.row_task_list_cb_done);
cardView = (CardView) itemView.findViewById(R.id.cardView);
}
}
private Date getDate(int day) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, day);
return calendar.getTime();
}
protected TodoModel getTask(int position) {
return getData().get(position);
}
protected void updateTask(int position, TodoModel task) {
realm.beginTransaction();
TodoModel newTask = realm.where(TodoModel.class).equalTo("id", task.getId()).findFirst();
newTask.setDate(task.getDate());
newTask.setDone(task.isDone());
newTask.setName(task.getName());
realm.commitTransaction();
}
protected void removeTask(int position) {
TodoModel newTask = realm.where(TodoModel.class).equalTo("id", getTask(position).getId()).findFirst();
realm.beginTransaction();
newTask.deleteFromRealm();
realm.commitTransaction();
notifyItemRemoved(position);
}
}
崩溃报告
09-10 12:25:57.876 7332-7332/realmtest.com.to_do_list_test E/AndroidRuntime: FATAL EXCEPTION: main
Process: realmtest.com.to_do_list_test, PID: 7332
java.lang.ArrayIndexOutOfBoundsException: Out of range in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 133(requested: 1 valid: 1)
at io.realm.internal.Collection.nativeGetRow(Native Method)
at io.realm.internal.Collection.getUncheckedRow(Collection.java:386)
at io.realm.OrderedRealmCollectionImpl.get(OrderedRealmCollectionImpl.java:106)
at io.realm.RealmResults.get(RealmResults.java:53)
at io.realm.OrderedRealmCollectionImpl.get(OrderedRealmCollectionImpl.java:19)
at realmtest.com.to_do_list_test.activity.TodoAdapter.getTask(TodoAdapter.java:157)
at realmtest.com.to_do_list_test.activity.TodoAdapter.onClick(TodoAdapter.java:106)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
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:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
getData() 的实现
@Nullable
public OrderedRealmCollection<T> getData() {
return adapterData;
}
任务活动Class
public class TaskActivity extends AppCompatActivity implements TodoAdapter.TaskListener{
private static final int ADD_TASK_REQUEST_CODE = 1000;
private static final int EDIT_TASK_REQUEST_CODE = 1001;
private Realm realm;
private RecyclerView recyclerView;
private TodoAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_todo_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("ToDo List");
setSupportActionBar(toolbar);
realm = Realm.getDefaultInstance();
recyclerView =(RecyclerView)findViewById(R.id.activity_tasks_ll_task);
setUpRecycler();
// Variables
// Views
FloatingActionButton addFloatingActionButton = (FloatingActionButton) findViewById(R.id.activity_tasks_fab_add);
//Listeners
addFloatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(new Intent(getApplicationContext(), TodoAddActivity.class), ADD_TASK_REQUEST_CODE);
}
});
}
private void setAdapter() {
adapter = new TodoAdapter(this, realm.where(TodoModel.class).findAll(),this,realm);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void setUpRecycler() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
// use a linear layout manager since the cards are vertically scrollable
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
setAdapter();
}
}
image1
image2
您在删除条目后更改了适配器列表,但没有通知适配器您更改了列表的大小。因此,您必须告诉适配器列表的大小已更改。
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) { //Error for this line
removeTask(position);
notifyDataSetChanged(); <-------------------Add this line to your code.
return;
}
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
});
无论何时更改适配器列表的大小时,都必须通过调用函数 notifyDataSetChanged().[= 显式告知适配器有关更改的信息11=]
从 if (getTask(position).isDone()) {
中删除 return 语句并将 AlertDialog
放在 if 的 else 子句中,如下所示。
holder.deleteImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getTask(position).isDone()) {
removeTask(position);
notifyDataSetChanged();
}else {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("Confirm Delete?");
alertDialog.setMessage("Do you want to delete the task you created?");
alertDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
removeTask(position);
}
});
alertDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
}
});
notifyDataSetChanged()
可以用
但是如果您想显示动画以及更新列表中的项目位置
在sequest中使用此代码
notifyItemRemoved(position)
MH: 用于删除项目并显示动画
notifyItemRangeChanged(position, ListSize);