ItemtouchHelper导致索引超出范围异常

时间:2018-03-06 00:35:53

标签: android android-recyclerview itemtouchhelper

我有一个私有的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的视图中完全消除了一次项目的两次滑动,有时它不会删除我正在刷的内容

1 个答案:

答案 0 :(得分:0)

我发现问题确实存在于项目触摸助手上; 具体来说,他们是我检索数据的方式。

在我的onSwipe我会打电话通过以下方法获取我正在刷的项目:

mData.deleteTask(mData.getAllToDo().get(viewHolder.getAdapterPosition()));

这个问题是getAllToDo()方法将返回当前的数据库项列表(即使列表未更改),而不是适配器中保存的列表。

为了解决这个问题,我重新实现了以下几行:

`mData.deleteTask(mData.getAdapter()getResults()得到(viewHolder.getAdapterPosition())。);

getAdaper()检索我正在使用的适配器,getResults()检索适配器当前使用的列表。然后正确识别对象并将其从数据库中删除,一切正常。

请注意,如果您接收到如下错误:java.lang.IndexOutOfBoundsException:检测到不一致,那是因为您正在将主机线程的不同线程中的适配器数据更改。

可在此处找到解决方案:

RecyclerView and java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder in Samsung devices