I have a private ItemTouchHelper that delete a row from a room database however currently it's cause an ArrayIndexOutOfBounds exception when I swiping to delete:
FATAL EXCEPTION: main
Process: xxx.xxx.xxx.xxx, PID: 6327
java.lang.ArrayIndexOutOfBoundsException: length=1; index=-1
I've posted a similar question however now I've distilled the source of the problem being the itemTouchHelper.
The itemtouch helper is attached to a RecycleViewAdapter that gets it's dataset from a room database.
The dataset is displayed as a list and i'm using the itemTouchHelper's viewHolder.getAdapterPosition to delete the item at the position that has been swiped in the RecycleAdapter. Is this causing me issues?
I've attached the relevant code:
database handling code in 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);
}
}
}
fragment with 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();
}
}
}
I've noted from debugging that it takes 2 swipes for an item to fully dissapear from the RecycleAdapter's view and sometimes it does not delete what I'm swiping