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

如何在MVVM android应用程序中使用存储库模式和实时数据对列表进行正确排序?,android,sorting,mvvm,viewmodel,repository-pattern,Android,Sorting,Mvvm,Viewmodel,Repository Pattern,我正在为android编写一个简单的待办事项列表风格的应用程序,我在添加排序功能方面遇到了问题 我有一个屏幕,屏幕上显示了属于用户的所有列表,我想添加一个功能,允许用户打开或关闭排序。问题是,我似乎无法找到一种方法,使显示给用户的列表在再次更改后保持一致的排序 假设列表保存在房间数据库中。 实现我想要的最简单、最一致的方法是对数据库本身中的数据进行排序,但这可能不是一种方法,因为实现起来会很复杂(如果可能的话) 我很可能应该在视图模型中对数据进行本地排序。我想我可以使用MediatorLiveD

我正在为android编写一个简单的待办事项列表风格的应用程序,我在添加排序功能方面遇到了问题

我有一个屏幕,屏幕上显示了属于用户的所有列表,我想添加一个功能,允许用户打开或关闭排序。问题是,我似乎无法找到一种方法,使显示给用户的列表在再次更改后保持一致的排序

假设列表保存在
房间
数据库中。 实现我想要的最简单、最一致的方法是对数据库本身中的数据进行排序,但这可能不是一种方法,因为实现起来会很复杂(如果可能的话)

我很可能应该在视图模型中对数据进行本地排序。我想我可以使用
MediatorLiveData
来实现这一点,它将观察数据库,而主机活动则会观察数据库本身。在更新
MediatorLiveData
之前,我会使用标记
isSorting
对列表进行排序,以原样返回数据或在传递结果之前对其进行排序

我的问题的关键是,我希望能够打开和关闭此功能,同时在之后(当执行另一个操作时)仍然保持数据的顺序。以下是一个典型事件流的示例:

  • 用户打开应用程序,数据库返回:“列表3”、“列表1”、“列表2”
  • 数据按原样显示给用户(未排序)
  • 用户打开排序功能
  • 视图模型在本地对支持列表进行排序
  • 活动中的观察者接收已排序的列表
  • 活动现在显示“列表1”、“列表2”、“列表3”
  • 用户添加一个新列表:“列表4”
  • 在讨论问题部分之前,下面是一些代码:

    存储库(为简洁起见缩短):

    Viewmodel(为简洁起见缩短)

    class UserListsViewModel(val userId:Int,val repository:ListsRepository):ViewModel(){
    val allLists=MediatorLiveData()
    val isSorting=false
    初始化{
    allLists.addSource(repository.getAllUserList(userId)){userLists->
    val结果=用户列表
    如果(i排序){
    result=result.sortedBy{it.name}
    }
    值=结果
    }
    }
    }
    
    现在让我们进入实际问题:

    只要打开排序功能,一切正常,用户将看到“列表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应用程序中提供排序功能的“标准方式”是什么


    谢谢

    我认为你的假设有问题

    现在让我们进入实际问题:

    只要打开排序功能,一切正常,用户将看到“列表1”、“列表2”、“列表3”、“列表4”

    但是现在,假设用户关闭了排序功能,并添加了另一个列表,“列表0”

    [……]

    期望结果:“列表1”、“列表2”、“列表3”、“列表4”、“列表0”(未排序,但保留以前的顺序)

    实际结果:“列表3”、“列表1”、“列表2”、“列表4”、“列表0”(列表1、2、3之前的排序现在丢失)

    作为用户,我希望在打开或关闭排序后立即更改排序行为。因此,在用户关闭排序后,项目的显示顺序将再次为:“列表3”、“列表1”、“列表2”、“列表4”。当添加另一个列表时,它将(不进行排序)追加到末尾,就像您编写的那样,但不会对用户进行意外的排序更改

    如果您真的想实现上面描述的功能,我想您必须在表中添加一个
    sort\u index
    字段作为排序标准。然后,当您按列表标题、创建日期等进行排序时,可以更新该字段。然后,当您按此字段排序时(您也可以让room/数据库为您排序,这样会更高效),用户将获得应用程序的一致行为

    更高级的方法是创建一个额外的“映射”表,其中有一列用于列表索引,另一列用于实际顺序(
    sort\u index
    )。当然,该列表也可以保存在视图模型中,而不是数据库中的字段/表,因为它可以动态创建


    使用此字段的另一个好处是,它允许您的用户通过拖放手动排序列表,您只需相应地更新索引。

    这是我遇到的另一个问题,也是我决定采用的解决方案(希望这能帮助其他人):

    首先,我采用了建议的方法,即在用户单击“排序”按钮后立即更改排序顺序。这意味着,我不再按照“现在是它的排序,现在不是”,而是将其视为“数据总是按某些东西排序(即使它是“未排序的”)。 我希望“未排序”列表(默认排序)与数据库中显示的项目的顺序相同,但是我的
    ViewModel
    的设置方式使我无法
    class ListsRepository {
        val db = Database().getInstance();
        
        fun getAllUserLists(userId: Int): LiveData<List<UserList>>
    }
    
    class UserListsActivity: Activity() {
    
        val viewModel: UserListsViewModel    
        val adapter: UserListAdapter
    
        fun onCreate(savedInstanceState: Bundle?) {
            viewModel.allLists.observe(this, Observer { newData ->
                adapter.setData(newData)
                adapter.notifyDataSetChanged()
            )
        }
    }
    
    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
            }
        }
    
    }
    
    //inside view model class
    val allLists : LiveData<List<UserList>> = repository.getAllLists()