我有一个由ResourceCursorAdapter填充的ListView。我使用loaders机制向ContentProvider查询列表项。我检测列表项上的滑动手势以对它们执行某些操作。新项目由后台服务添加,因此列表可以动态更改。
一切正常,除非我开始滑动并发生数据库更改(后台服务添加新行的结果)。在这种情况下,未正确检测到手势。我注意到ACTION_CANCEL被调度到列表项视图,并且还对所有可见项执行bindView。在bindView方法中我只设置了一些文本 - 我不会在那里更改任何监听器。
即使后台服务添加新项目,我怎样才能使手势工作?也许有一种方法可以防止动作被取消,或者我可以暂停数据库更新,这样它们就不会中断手势。
答案 0 :(得分:0)
在您的ResourceCursorAdapter中为newView()
中的视图设置触控侦听器。您可能需要修改适配器的构造函数以传递触摸侦听器以在newView()
中使用。
答案 1 :(得分:0)
您需要将更新分离到数据和UI。这有点难看。
1)不要使用游标适配器。将结果从游标加载到某个数据结构中,并使适配器使用该数据副本。然后,当您获得新数据时,创建该数据结构的新副本,然后将其保存到适配器查看的变量并调用notifyDataSetChanged。这样就不会链接更改光标和更新屏幕。
2)当服务更新光标时,不要自动更新列表视图。然后继承ListView。从服务获得更新时,请保存新数据,但不要更新列表视图。相反,设置一个标志。在新的ListView子类中,重写onTouchEvent,以便在发生ACTION_UP事件时,还检查该标志。如果设置了标志,则将其设置为false,然后在适配器上将notifyDataSetChanged设置为false。这样,在用户完成滚动之前,列表不会更新。
答案 2 :(得分:0)
我最终用以下方法解决了这个问题。
在我的列表适配器中,我有一个标志:
private boolean mIsSwiping;
我在用户开始滑动时将其设置为true,在任何滑动操作完成时将其设置为false(可能是通过自动动画)。
在getView()的顶部,我检查标志的值,并在需要时提前返回。这可以防止重新绘制错误的列表视图项。
if (convertView != null && mIsSwiping) {
return convertView;
}
此外,在使用适配器的片段中,我有类似的逻辑,但将其应用于游标加载逻辑:
private Cursor mNewCursor;
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (mListAdapter.isSwiping()) {
mNewCursor = cursor;
} else {
mListAdapter.swapCursor(cursor);
mNewCursor = null;
}
}
然后在相同的片段中,在将mListFragment的mIsSwiping标志设置为false之前:
if (mNewCursor != null) {
mListFragment.swapCursor(mNewCursor);
mNewCursor = null;
}
希望这会有所帮助 - 它真的只是通过一些具体的代码充实了Gabe的答案。
您可能需要单独跟踪的一件事是mNewCursor在交换之前是否已关闭。我自己没有遇到过这个问题,但YMMV。