22

我在 android 中使用 Snackbar,并且我已经实现了一个操作,以便用户可以撤消该操作(该操作正在清除列表视图中的所有项目)。删除项目并将其添加回列表视图已经完成并且工作正常。

我的问题是,项目存储在 sqlite 数据库中,如何从表中删除项目?(我怎么知道用户没有点击撤消按钮,这样我才能完全从数据库中删除数据)。

这是OnOptionsItemSelected()中的代码

case R.id.action_clear:
        final List<Word> temp = new ArrayList<Word>(data);
        data.clear();
        adapter.notifyDataSetChanged();
        View view = findViewById(R.id.layoutFavWords);
        Snackbar.make(view,"Deleted Saved Selection.", Snackbar.LENGTH_LONG).
        setAction("Undo", new OnClickListener() {

            @Override
            public void onClick(View v) {
                for(Word word:temp)
                    data.add(word);
                adapter.notifyDataSetChanged(); 
            }

        }).show();
        break;

所以如果用户在snackbar的可见期间没有点击撤消按钮,那么我需要从数据库中永久删除数据。

有什么解决方案吗?

4

5 回答 5

31

据我所知,这是设计使然。你应该:

  • 用户点击删除按钮后立即删除该项目;
  • 将其临时存储在类变量中;
  • 如果用户点击撤消,则将该项目再次添加到数据库中。

这种方法更安全、更稳健;你不应该等待小吃店被解雇,因为那个动作甚至不可能发生。试想一下用户在snackbar 仍然打开时强制退出应用程序:该项目是否应该被删除?它应该。

更值得信赖的来源是 Ian Lake 的 g+ 帖子(由于 G+ 弃用而被删除)。在评论中,您可以阅读:

您希望您的 UI 立即做出反应(而不是等待小吃栏消失)——大多数系统(尤其是那些同步到外部服务器的系统)都有“软删除”的概念,其中的东西被标记为已删除。在这些情况下,撤消操作只是将记录取消标记为已删除。即使用户在小吃栏完成之前离开应用程序,这个系统也能正常工作(你不能假设小吃栏总是会完成它的动画!)。

最简单的方法是将记录临时保存在其他地方(甚至是局部变量),然后如果碰巧点击了撤消按钮,则重新插入它。

于 2015-06-25T18:24:34.467 回答
11

Android 支持库 v23 添加了Snackbar.Callback,您可以使用它来侦听零食栏是否被用户关闭或超时。

从astinx的帖子中借用的示例:

Snackbar.make(getView(), "Hi there!", Snackbar.LENGTH_LONG).setCallback( new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                switch(event) {
                    case Snackbar.Callback.DISMISS_EVENT_ACTION:
                        Toast.makeText(getActivity(), "Clicked the action", Toast.LENGTH_LONG).show();
                        break;
                    case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                        Toast.makeText(getActivity(), "Time out", Toast.LENGTH_LONG).show();
                        break;
                }
            }

            @Override
            public void onShown(Snackbar snackbar) {
                Toast.makeText(getActivity(), "This is my annoying step-brother", Toast.LENGTH_LONG).show();
            }
        }).setAction("Go away!", new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        }).show();
于 2015-10-18T09:36:03.147 回答
6

例子:

final java.util.Timer timer = new Timer();
Snackbar snackbar = Snackbar.make(...).setAction("Undo", new OnClickListener() {
        @Override
        public void onClick(View v) {
            timer.cancel();
            for(Word word:temp)
                data.add(word);
            adapter.notifyDataSetChanged(); 
        }
    }).show();
timer.schedule(new TimerTask() {
    public void run() {
        // delete from db
    }
}, snackbar.getDuration());

给snackbar.getDuration() 增加一点时间(100-200 毫秒?)可能是个好主意,因为定时器在时间方面不是很精确,这样它们可能会在snackbar 即将关闭之前被调用,尽管在这种情况下可能性很小。

于 2015-06-25T18:06:49.860 回答
3

如果您不想立即从数据库中删除记录,请尝试以下操作:

// Backup the item for undo
int itemIndex = viewHolder.getAdapterPosition();
Item item = adapter.getItem(itemIndex);

// Delete only from the adapter
adapter.removeItem(itemIndex);

Snackbar.make(getView(), "Item deleted", LENGTH_LONG)
        .addCallback(new BaseCallback<Snackbar>() {
            public void onDismissed(Snackbar transientBottomBar, int event) {
                if (event != DISMISS_EVENT_ACTION) {
                    // Dismiss wasn't because of tapping "UNDO"
                    // so here delete the item from databse
                }
            }
        })
        .setAction("UNDO", v -> adapter.addItem(item, itemIndex))
        .show();
于 2018-12-31T13:55:27.453 回答
0

我的方法是将“已删除”列设为布尔值,如果已删除,只需将 stat 更改为 true,然后撤消以将 stat 更改回 false,您也可能希望垃圾控制器或调度程序每周删除所有错误值。

于 2019-04-23T10:43:44.943 回答