【问题标题】:In a snackbar action, how can I be sure it's safe to permanently delete a soft-deleted record from the database?在小吃店操作中,如何确保从数据库中永久删除软删除记录是安全的?
【发布时间】:2015-09-12 10:46:37
【问题描述】:

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

有什么解决办法吗?

【问题讨论】:

  • 立即删除它们,如果按下撤消则重新插入?
  • 是的,这是另一种选择。但是有什么办法可以实现我想要做的吗?仅当用户未单击撤消按钮时才删除
  • imo 已经足够好了。您假设用户知道他想要什么,但他可以改变主意(撤消)。或者您可能想要一个confirm-like 小吃店。查看文档,它看起来不过是 Toast
  • 如果没有办法实现它,我必须这样做。感谢回复
  • 如果用户删除数据然后杀死你的应用会发生什么?记录会留在数据库中,这是不对的,删除按钮应该立即删除记录,您需要保存此记录的临时用于UNDO,在选择UNDO时您需要再次将其插入数据库并重新加载列表。

标签: java android android-support-library android-design-library snackbar


【解决方案1】:

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

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

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

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

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

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

【讨论】:

  • 在强制退出的情况下,如果用户想撤消怎么办?最好有数据以防失败,因为用户再次删除只是轻点一下,但再次创建数据不会相对容易,在某些情况下是不可能的,例如在数据具有一些传感器读数的情况下。当然,UI 应该立即做出反应,就我而言,我有两个集合,一个用于项目,一个用于垃圾。所以该项目被移动到垃圾箱。数据库更新是在稍后的时间点进行的,与每次更改时的数据库操作相比,UI 的运行速度非常安静。
  • 标记删除,在应用程序启动时运行额外的清理任务以清理任何可能从裂缝中溜走的挥之不去的记录(即当 Snackbar 被关闭时没有被清理)..或甚至重置他们的删除标志。这样一来,您还可以为用户提供另一个撤消的机会……这比在应用程序被杀死/手机死机/屏幕破裂之前意外删除某些内容并丢失撤消按钮更糟糕。
【解决方案2】:

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

示例借自astinxs 帖子:

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

【讨论】:

  • “Go away” onClick 不应该包含对dismiss() 的调用吗?
  • Snackbars setAction() 方法处理关闭小吃店,因此您不必自己动手。
【解决方案3】:

例子:

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-200ms?)上增加一点可能是个好主意,因为定时器在时间方面不是很精确,这样它们可能会在snackbar 即将到来之前被调用关闭,尽管在这种情况下可能性很小。

【讨论】:

  • snackbar.getDuration() 为零。它是如何在屏幕上停留几秒钟的?
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 2010-11-16
      • 2023-03-26
      • 2013-08-03
      相关资源
      最近更新 更多