android - 如何使用MVVM Android应用程序中的存储库模式和实时数据正确地对列表进行排序?

标签 android sorting mvvm viewmodel repository-pattern

我正在为Android编写一个简单的待办事项列表样式应用程序,但在添加排序功能时遇到了问题。
我有一个带有RecyclerView的屏幕,该屏幕显示了属于该用户的所有列表,并且我想添加一个功能,该功能允许用户打开或关闭排序。问题是我似乎无法找到一种方法来使显示给用户的列表在进行另一次更改后保持一致的排序。
可以说列表保存在Room数据库中。
实现我想要的最简单,最一致的方法是对数据库本身中的数据进行排序,但这可能不是可行的方法,因为实现起来很复杂(即使可能)。
我很可能应该在 View 模型中对数据进行本地排序。我想我可以使用MediatorLiveData做到这一点,它可以观察数据库,而主机 Activity 本身可以观察数据库。在更新MediatorLiveData之前,我将使用标记isSorting对列表进行排序,以按原样返回数据或在传递结果之前对数据进行排序。
我的问题的关键是我希望能够打开和关闭此功能,同时仍保持数据顺序(执行其他操作时)。这是典型事件流的示例:

  • 用户打开应用程序,数据库返回:“列表3”,“列表1”,“列表2”。
  • 数据按原样(未排序)显示给用户
  • 用户打开排序功能
  • View 模型在本地对后备列表进行排序
  • Activity 中的观察者收到排序后的列表
  • 该 Activity 现在显示“列表1”,“列表2”,“列表3”
  • 用户添加一个新列表:“列表4”。

  • 在进入问题部分之前,下面是一些代码:
    存储库(为简便起见,简称:)
    class ListsRepository {
        val db = Database().getInstance();
        
        fun getAllUserLists(userId: Int): LiveData<List<UserList>>
    }
    
    Activity (为简洁起见,简称:)
    class UserListsActivity: Activity() {
    
        val viewModel: UserListsViewModel    
        val adapter: UserListAdapter
    
        fun onCreate(savedInstanceState: Bundle?) {
            viewModel.allLists.observe(this, Observer { newData ->
                adapter.setData(newData)
                adapter.notifyDataSetChanged()
            )
        }
    }
    
    View 模型(为简洁起见,简称)
    class UserListsViewModel(val userId: Int, val repository: ListsRepository ): ViewModel() {
    
        val allLists = MediatorLiveData<List<UserList>>()
        val isSorting = false
    
        init {
            allLists.addSource(repository.getAllUserLists(userId)) { userLists ->
                val result = userLists
                
                if(isSorting) {
                    result = result.sortedBy { it.name }
                }
            
                value = result
            }
        }
    
    }
    
    现在开始讨论实际问题:
    只要打开排序功能,一切都很好,用户将看到“列表1”,“列表2”,“列表3”,“列表4”。
    但是现在,假设用户关闭了排序功能,并添加了另一个列表“列表0”
    现在发生的是:
  • MediatorLiveData从数据库接收更新,如“列表3”,“列表1”,“列表2”,“列表4”,“列表0”(数据库的原始顺序以及新列表)。
  • isSorting标志处于关闭状态,因此它将值按原样设置为返回的数据
  • 数据按未排序显示给用户,但是以前的排序现在丢失了

  • 所需结果:“列表1”,“列表2”,“列表3”,“列表4”,“列表0”(未排序,但保留了先前的顺序)
    实际结果:“列表3”,“列表1”,“列表2”,“列表4”,“列表0”(现在丢失了列表1,2,3的先前排序)。
    我希望我能说清楚。是否可以在不增加太多复杂性的情况下实现?在Android应用中提供排序功能的“标准方法”是什么?
    谢谢

    最佳答案

    我认为您的假设有问题

    Now lets get to the actual issue:

    As long as the sorting feature is turned on, everything is fine and the user will see "list 1", "list 2", "list 3", "list 4".

    But now, lets say the user turns the sorting feature off, and adds another list, "list 0"

    [...]

    Desired result: "list 1","list 2","list 3","list 4","list 0" (unsorted, but previous order is kept)

    Actual result: "list 3","list 1","list 2","list 4","list 0" (the previous sorting of lists 1,2,3 is now lost).


    作为用户,我希望在打开或关闭排序后立即更改排序行为。因此,在用户关闭排序之后,显示的项目顺序将再次为:“列表3”,“列表1”,“列表2”,“列表4”。然后,当添加另一个列表时,就像您所写的那样,该列表将(不进行排序)附加到末尾,但对于用户而言,排序更改不会令人惊讶。
    如果您确实想要实现上述功能,我想您将不得不在表中添加sort_index字段作为排序标准。然后,当您按列表标题,创建日期等进行排序时,可以更新该字段。然后,当您按此字段排序时(您还可以让房间/数据库为您服务,这应该更高效),用户将获得应用程序的一致行为。
    更高级的做法是创建一个额外的“映射”表,该表的一列用于列表的索引,第二列用于实际的顺序(上面的sort_index)。当然,该列表也可以保存在您的 View 模型中,而不是数据库中的字段/表,因为它可以即时创建。
    拥有此字段的另一个好处是,它将允许您的用户通过拖放来手动对列表进行排序,而您只需要相应地更新索引即可。

    关于android - 如何使用MVVM Android应用程序中的存储库模式和实时数据正确地对列表进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62866270/

    相关文章:

    php - 在 PHP 中对关联数组进行排序

    wpf - MVVM-应该将动态生成和加载XAML的代码放在哪里?

    javascript - Breeze.js EntityManager 未检测到更改

    android - 使用 'immersive mode' 检测系统按钮何时可见

    android - y + height 在 android 中必须 <= bitmap.height()

    MongoDB查找子文档并对结果进行排序

    c# - 对多对象列表进行排序的正确方法?

    silverlight - 对 MVVM 模式的反对是缺乏 IDE 支持——有任何框架对此有帮助吗?

    android - 云防火墙 : does updating the same document twice in a batch count as a single write?

    java - 将 RippleEffect Color 更改回其 Styled 原始值