我有一个私有的ItemTouchHelper,可以删除房间数据库中的一行,但是当我滑动删除时,它会导致一个ArrayIndexOutOfBounds异常:
FATAL EXCEPTION: main
Process: xxx.xxx.xxx.xxx, PID: 6327
java.lang.ArrayIndexOutOfBoundsException: length=1; index=-1
我发布了一个类似的问题但是现在我已经将问题的根源提炼为itemTouchHelper。
itemtouch帮助程序附加到RecycleViewAdapter,后者从房间数据库中获取数据集。
数据集显示为列表,并使用itemTouchHelper的viewHolder.getAdapterPosition 来删除在RecycleAdapter中刷过的位置的项目。这会引起我的问题吗?
我已附上相关代码:
mainActivity.java中的数据库处理代码
@Override
public boolean searchTerm(String title) {
try {
this.dbThread.submit(() -> {
this.searchResults = this.userData.listModel().searchByTitle(title);
});
this.mRecycleAdapter.reloadAdapterData(this.searchResults);
this.mRecycleAdapter.notifyDataSetChanged();
Log.d(TAG, "Search Successful!");
return true;
} catch (Exception e) {
Log.d(TAG, "Search Failed \n -See Console");
return false;
}
}
@Override
public void addTask(GlobalLists item) {
this.dbThread.submit(() -> {
this.userData.listModel().insertItem(item);
});
}
@Override
public List<GlobalLists> getAllToDo() {
this.dbThread.submit(() -> {
this.searchResults = this.userData.listModel().loadAllLists();
});
return this.searchResults;
}
@Override
public List<GlobalLists> getResults() {
return this.searchResults;
}
@Override
public RecycleViewAdapter getAdapter() {
return this.mRecycleAdapter;
}
@Override
public void refresh() {
try {
this.dbThread.submit(() -> {
this.mRecycleAdapter.reloadAdapterData(this.userData.listModel().loadAllLists());
});
this.mRecycleAdapter.notifyDataSetChanged();
} catch (Exception e) {
Toast.makeText(this, "Refresh Failed", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
@Override
public void completeTask(GlobalLists item) {
try {
this.dbThread.submit(() -> {
this.userData.listModel().completeTask(new CompletedTasks(item.getTitle(), item.getContents()));
this.userData.listModel().deleteItem(item);
});
this.refresh();
Log.d(item.getTitle(), "Task Completed!");
} catch (Exception e) {
Toast.makeText(this, "Complete Task Failed", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
@Override
public void deleteTask(GlobalLists item) {
try {
this.dbThread.submit(() -> {
this.userData.listModel().deleteItem(item);
});
this.refresh();
Log.d(item.getTitle(), "Task Deleted");
} catch (Exception e) {
e.printStackTrace();
}
}
RecycleViewAdapter
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>{
private LayoutInflater inflater = null;
private List<GlobalLists> results = null;
public RecycleViewAdapter(Context context, List<GlobalLists> results){
this.inflater = LayoutInflater.from(context);
this.results = results;
}
@NonNull
@Override
public RecycleViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_row, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
GlobalLists item = this.results.get(position);
holder.rowTitle.setText(item.getTitle());
}
public void reloadAdapterData(List<GlobalLists> refresh){
this.results = refresh;
}
@Override
public int getItemCount() {
return this.results == null ? 0 : this.results.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView rowTitle = null;
private ImageView rowImage = null;
private CheckBox completedCheck = null;
public ViewHolder(View itemView) {
super(itemView);
this.rowTitle = itemView.findViewById(R.id.rowTitle);
this.rowImage = itemView.findViewById(R.id.rowImage);
this.completedCheck = itemView.findViewById(R.id.completedCheck);
}
}
}
带有itemTouchHelper的片段
public class showAllLists_fragment extends android.support.v4.app.Fragment {
private static final String TAG = "showAllLists";
private RecyclerView mAllItemsView = null;
private DataCommunication mData = null; //interface for communicating between Activity and fragment.
private ItemTouchHelper itemTouchHelper = null;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.show_all_lists_frag, container, false);
this.mAllItemsView = (RecyclerView) view.findViewById(R.id.allItems);
this.itemTouchHelper = new ItemTouchHelper(this.createHelperCallBack());
this.itemTouchHelper.attachToRecyclerView(this.mAllItemsView);
this.mAllItemsView.setAdapter(this.mData.getAdapter());
this.mAllItemsView.setLayoutManager(new LinearLayoutManager(getActivity()));
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
this.mData = (DataCommunication) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement DataCommunication");
}
}
private ItemTouchHelper.Callback createHelperCallBack() {
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
if (direction == ItemTouchHelper.LEFT) {
mData.deleteTask(mData.getAllToDo().get(viewHolder.getAdapterPosition()));
mData.getAdapter().notifyItemRemoved(viewHolder.getAdapterPosition());
} else if (direction == ItemTouchHelper.RIGHT) {
mData.completeTask(mData.getAllToDo().get(viewHolder.getAdapterPosition()));
mData.getAdapter().notifyItemRemoved(viewHolder.getAdapterPosition());
}
}
};
return simpleCallback;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
this.mData.refresh();
}
}
}
我已经从调试中注意到,从RecycleAdapter的视图中完全消除了一次项目的两次滑动,有时它不会删除我正在刷的内容
答案 0 :(得分:0)
我发现问题确实存在于项目触摸助手上; 具体来说,他们是我检索数据的方式。
在我的onSwipe
我会打电话通过以下方法获取我正在刷的项目:
mData.deleteTask(mData.getAllToDo().get(viewHolder.getAdapterPosition()));
这个问题是getAllToDo()
方法将返回当前的数据库项列表(即使列表未更改),而不是适配器中保存的列表。
为了解决这个问题,我重新实现了以下几行:
`mData.deleteTask(mData.getAdapter()getResults()得到(viewHolder.getAdapterPosition())。);
getAdaper()
检索我正在使用的适配器,getResults()
检索适配器当前使用的列表。然后正确识别对象并将其从数据库中删除,一切正常。
请注意,如果您接收到如下错误:java.lang.IndexOutOfBoundsException:检测到不一致,那是因为您正在将主机线程的不同线程中的适配器数据更改。
可在此处找到解决方案: