1

我有一个私人 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();
        }

    }

回收视图适配器

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();
        }
    }

}

我从调试中注意到,一个项目需要 2 次滑动才能从 RecycleAdapter 的视图中完全消失,有时它不会删除我正在滑动的内容

4

1 回答 1

0

我发现问题确实出在 item touch helper 上;具体来说,他们是我检索数据的方式。

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

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

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

因此,为了解决这个问题,我重新实现了该行,如下所示:

`mData.deleteTask(mData.getAdapter().getResults().get(viewHolder.getAdapterPosition()));

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

请注意,如果您随后收到如下错误:java.lang.IndexOutOfBoundsException: Inconsistency detected,那么这是因为您正在将不同线程中的适配器数据更改为您的主线程。

可以在这里找到解决方案:

RecyclerView 和 java.lang.IndexOutOfBoundsException:检测到不一致。三星设备中的无效视图支架适配器 positionViewHolder

于 2018-03-06T10:50:34.220 回答