【问题标题】:SQLite Change Sort Order for items on databaseSQLite 更改数据库上项目的排序顺序
【发布时间】:2013-02-25 16:19:38
【问题描述】:

想象一下这是我的数据库的快速模型:

数据库中的项目按列表呈现给用户,每个列表显示在一个新片段上,这些片段显示在视图页面上。因此,假设在这种假设情况下,viewpager 上有两个片段,第一个片段将显示 first_list,第二个片段将显示 second_list。这是该查询的代码:

 public static Cursor getListItems (final Context context, String listName) {
    if (mDatabase == null || !mDatabase.isOpen())
        open(context);  //This gets the writable db.

    String where = LIST_NAME + " = '" + listName + "'";
    return mDatabase.query(TABLE_LIST_ITEMS, PROJECTION_LIST_ITEMS, 
    where, null, null, null, SORT_ORDER);
}

其中SORT_ORDERorder_in_list,这很好用,首先。

现在,列表视图可以使用公共library 重新排列,它试图允许用户控制每个列表中项目的顺序。这是我遇到问题的地方,光标没有add(int index, Object object),或者其他一些简单的方法来管理排序。我首先认为我可以简单地调用mDatabase.update() 来更改order_in_list 的值,但这可行,但结果并不如预期。例如,用户将 item two 拖动到 zero 的位置,记住:零索引值,我们现在将有 two 个带有 order_in_list 的项目零。尽管我可以在 item one 上调用 mDatabase.update() 将他的位置更新为 one,但想象一下在格式良好的数据库中处理多个项目需要做多少工作.

有人对我如何解决这个问题有什么好的建议吗?我认为我通过添加额外的 col 来进行排序很聪明:(

INB4:

是的,我知道数组可以很好地处理这个问题。但该数据库不仅存储 4 个列,它还有更多字段。每次从数据库中填充数组都是浪费时间和精力。无论如何,我必须在应用程序关闭时写回数据库。

编辑 所以我将列表视图更改为仅显示一个文本字符串,并在实际单击项目时显示更多列(因此显示具有指定列表项数据的新片段)。这让我可以简单地保留一个 ArrayAdapter 来轻松处理拖放操作。在 onStop 期间,我仅在需要保存更改时才更新引用:

@Override
public void onStop() {
    if (updateDbOnExit) {
        //Update rows on database.
        for (int i = 0; i < items.size(); i++) {
            //Set the order in list be the actual order on the array.
            Constants.LogMessage("Updating db content");
            DbManager.moveListItemTo(getActivity(), items.get(i), i);
        }
            updateDbOnExit = false;
    }
    super.onStop();
}   

MoveListItemTo 更新 order_in_list 的值:

 public static void moveTaskItemTo (final Context context, String item, int to) {
    if (mDatabase == null || !mDatabase.isOpen())
        open(context);  

    String where = COL_CONTENT + " = '" + item+ "'";

    ContentValues mContentValues = new ContentValues();
    mContentValues.put(ORDER_IN_LIST, to);  
    int rows = mDatabase.update(TABLE_LIST_ITEMS, mContentValues, where, null);

    Constants.LogMessage(rows + " row updated. Item moved to position: " + to);

    close();
}

现在可以了。但是,我仍然想知道是否有其他方法,尤其是当适配器使用数据库中多个 one 列中的数据时,因此需要使用 CusorAdapter 和不是常规的 ArrayAdapter,而后者又需要 Database 本身在每次拖放时更新,以通过 cursorAdapter.swapCursor() 在 UI 上反映更改。如前所述,每次拖动时更新ALL数据库中的项目(顺便说一句,实际上并不经常发生)是昂贵的,只更新行,将是一个更明智的选择。

【问题讨论】:

  • Where SORT_ORDER is order_in_list...。 Order_in_List 列,如果在后端查询中使用,将是“.... order by order_in_list”?
  • 不确定后端查询是什么意思。但在我的查询中,我将“order_in_list”作为查询方法的“order by”参数传递。

标签: android database sqlite


【解决方案1】:

I just meant I wanted a more effective way to update the fields in the db, rather than manually updating each and every single row

将用户指定顺序列设为小数,而不是整数。然后你只需要更新移动的行。

允许负数。

0.00 cat
1.00 aardvark
2.00 wolf
3.00 dog

如果将“dog”拖到“wolf”上方,则“dog”变为 1.50,无需更改其他行。如果将“aardvark”拖到“cat”上方(特殊情况——在列表之前而不是在行之间插入),则从最高值中减去 1,“aardvark”变为 -1.00。

这将要求您知道相邻行的值,但您不必更新它们。只有移动的行的值必须改变。

【讨论】:

  • 这种方法非常少见,想象在你的例子中,“dog”被拖到“wolf”之上,使“dog”成为1.5,如果我们现在将“aardvark”拖到“dog”之后怎么办,那会是什么数字?你会在那里遇到几个小数,而不是使用特定的数量来添加或减去计数。我想我接受你的第一个答案,因为我原来使用数组而不是占位符。
  • 如果 dog 被拖到 wolf dog 之上,则变为 1.5。如果我们在狗之后拖动土豚,土豚的值在 2.0 和 1.5 之间,例如1.75。十进制数允许用户进行成千上万次的重新定位——有限的、真实的,但对于现实世界的应用程序来说已经足够了。做拖放的人永远不会达到极限,除非他们在来世继续拖放。
  • 移动的行总是位于它后面的行和它前面的行之间的中间。你知道这两个值,然后计算中间位置。 movedRowPos = rowBeforePos + (rowAfterPos - rowBeforePos) / 2.00
  • 特殊情况是拖动行成为第一行或最后一行。然后,您只需将第一行/最后一行的位置值分别减去或加 1。
  • @gig6: "before" = 在显示顺序之前。您希望新位置位于 前后行的值之间。
【解决方案2】:

我建议您有一个额外的列 user_specified_order 表示用户通过拖放对 UI 中的行进行重新排序。

当其 user_specified_order 值因拖放重新定位而失效时,您必须更新每一行。何时保留该值由您决定——无论是在用户操作的“结束”时,但已定义(例如单击保存按钮)或在每次拖放后,如果没有“操作结束”的清晰 UI 指示器。

编辑:Android 中的 ContenProvider: Android - Can you update a Cursor for SQLite results?

Android SQLite 事务: Android Database Transaction

【讨论】:

  • 这是我添加的列,“order_in_list”是我尝试添加一个可以存储用户指定订单的附加列。但如前所述,当用户每次重新排列一个项目时,我只能更新被移动项目的值,并且根据示例,我最终会得到两个项目在拖动后具有相同的“order_in_list”。
  • 我认为 _order_in_list 是您的默认订单。查看我的扩展回复。
  • 你是对的,拖动后所有行的值在技术上都是无效的,但是我将如何在拖动后更新每一行的值?只需为每一行调用更新?
  • 我建议使用一个代理数组来保持用户指定的顺序,然后在您确定用户完成移动的任何时候从该代理数组更新数据库。您希望将该更新包装在事务中,因为它涉及多行。我在 SQLite 上做了很多工作,但在 Android 上没有,所以你必须问其他人如何在 Android 的事务中包装更新。
  • 一旦您将 UI 排序顺序与光标排序顺序“分离”,通过允许用户通过拖放重新定位行,您的问题不再是关于数据库排序顺序,而是关于如何更新光标中的行以反映 UI 排序顺序。您只需向每一行写入一个值,以反映其在 UI 中的顺序。应该编辑您的问题以反映您实际想要完成的任务。它实际上与排序顺序本身无关。
猜你喜欢
  • 1970-01-01
  • 2012-08-26
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多