在 snackbar 操作中,如何确保从数据库中永久删除软删除记录是安全的?

In a snackbar action, how can I be sure it's safe to permanently delete a soft-deleted record from the database?

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

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

这是OnOptionsItemSelcted()

里面的代码
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可见期间没有点击撤销按钮,那么我需要从数据库中永久删除数据。

有什么解决办法吗?

示例:

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 毫秒?)增加一点可能是个好主意,因为计时器在计时方面不是很准确,这样它们可能会在之前被调用快餐店即将关门,虽然这种情况下可能性很小。

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

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

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

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

you want your UI to react immediately (not wait for the snackbar to disappear) - most systems (particularly those that sync to an external server) have the concept of a 'soft delete' where things are marked as deleted. In those cases, an undo action would just be unmarking the record as deleted. This system works even if the user were to leave the app before the snackbar finishes (you can't assume the snackbar will always complete its animation!).

The easiest way to do that is to temporarily save the record elsewhere (even a local variable), then re-insert it if they happen to hit the undo button.

Android 添加了支持库 v23 Snackbar.Callback 如果快餐栏被用户关闭或超时,您可以使用它来收听。

示例借自 s post:

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

如果您不想立即从数据库中删除记录,试试这个:

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

我的方法是 hv "deleted" 列,它是布尔值,如果删除,只需将统计信息更改为 true 然后撤消以将统计信息更改回 false,您也可能希望垃圾控制器或调度程序删除所有每周的错误值。