как правильно отсортировать список с использованием шаблона репозитория и данных в реальном времени в приложении MVVM android? - PullRequest
0 голосов
/ 12 июля 2020

Я пишу простое приложение в стиле списка дел для android, и у меня возникли проблемы с добавлением функции сортировки.

У меня есть экран с RecyclerView, показывающий все списки, принадлежащие user, и я хотел бы добавить функцию, которая позволяет пользователю включать или отключать сортировку. Проблема в том, что я не могу найти способ, чтобы список, отображаемый для пользователя, оставался постоянно отсортированным после внесения другого изменения.

Допустим, списки хранятся в базе данных Room. Самый простой и наиболее последовательный способ добиться того, чего я хочу, - это отсортировать данные в самой базе данных, но, вероятно, это не путь к go, так как это было бы сложно реализовать (если даже возможно).

Скорее всего, мне следует отсортировать данные локально в моей модели представления. Я подумал, что могу сделать это, используя MediatorLiveData, который будет наблюдать за базой данных, а сам за ним будет наблюдать активность хоста. Перед обновлением MediatorLiveData я бы отсортировал список с помощью флага isSorting, чтобы либо вернуть данные как есть, либо отсортировать их перед доставкой результата.

Ключ к моему вопросу заключается в том, что я хочу иметь возможность включать и выключать эту функцию, сохраняя при этом порядок данных впоследствии (при выполнении другой операции). Вот пример типичного потока событий:

  1. Пользователь открывает приложение, и база данных возвращает: «список 3», «список 1», «список 2».
  2. данные отображаются пользователю как есть (несортированные)
  3. Пользователь включает функцию сортировки
  4. Модель представления сортирует список поддержки локально
  5. Наблюдатель в действии получает отсортированный список
  6. Действие теперь показывает «список 1», «список 2», «список 3»
  7. Пользователь добавляет новый список: «список 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()
        )
    }
}

Viewmodel (сокращено для краткости)

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».

Но теперь, допустим, пользователь отключает функцию сортировки и добавляет еще один список, «l ist 0 "

Теперь происходит следующее:

  1. MediatorLiveData получает обновление из базы данных как« список 3 »,« список 1 »,« список 2 »," список 4 "," список 0 "(исходный порядок в базе данных плюс новые списки)
  2. Флаг isSorting выключен, поэтому он устанавливает значение для возвращаемых данных как есть
  3. Данные отображаются пользователю без сортировки, но предыдущая сортировка теперь потеряна

Желаемый результат: «список 1», «список 2», «список 3», «список 4» , «список 0» (несортированный, но предыдущий порядок сохраняется)

Фактический результат: «список 3», «список 1», «список 2», «список 4», «список 0» (предыдущий сортировка списков 1,2,3 теперь потеряна).

Надеюсь, я ясно выразился. Можно ли этого добиться, не добавляя слишком много сложностей? Каков «стандартный способ» обеспечить функцию сортировки в приложении android?

Спасибо

Ответы [ 2 ]

2 голосов
/ 13 июля 2020

Я думаю, что в вашем предположении есть проблема

Теперь перейдем к фактической проблеме:

Пока функция сортировки включена, все в порядке и пользователь увидит «список 1», «список 2», «список 3», «список 4».

Но теперь, допустим, пользователь отключает функцию сортировки и добавляет еще один список, «список 0 "

[...]

Желаемый результат:« список 1 »,« список 2 »,« список 3 »,« список 4 »,« список 0 "(без сортировки, но предыдущий порядок сохраняется)

Фактический результат:" список 3 "," список 1 "," список 2 "," список 4 "," список 0 "(предыдущая сортировка списков 1 , 2,3 теперь потеряно).

Как пользователь я ожидал бы изменить поведение сортировки, как только я включу или выключу сортировку. Таким образом, после того, как пользователь отключил сортировку, порядок отображения элементов будет снова: «список 3», «список 1», «список 2», «список 4» . Когда затем добавляется другой список, он будет (без сортировки) добавлен в конец, как вы написали, но без неожиданного изменения сортировки для пользователя.

Если вы действительно хотите достичь того, что вы описали выше, Думаю, вам придется добавить в свою таблицу поле sort_index, которое будет использоваться в качестве критерия заказа. Затем вы можете обновить это поле при сортировке по заголовку списка, дате создания и т. Д. Когда вы затем сортируете по этому полю (что вы также можете позволить комнате / базе данных делать за вас, что должно быть более эффективным), пользователь получает согласованное поведение приложения.

Более продвинутым может быть создание дополнительная таблица «сопоставления», в которой есть столбец для индекса ваших списков и второй для фактического порядка (sort_index сверху). Конечно, этот список также может храниться в вашей модели представления, а не быть полем / таблицей в вашей базе данных, поскольку он может быть создан на лету.

Еще одним преимуществом наличия этого поля является то, что оно позволяет ваш пользователь может вручную отсортировать список с помощью перетаскивания, и вам просто нужно будет соответствующим образом обновить индексы.

0 голосов
/ 15 июля 2020

вот еще одна проблема, с которой я столкнулся, и решение, которое я решил использовать go (надеюсь, это поможет другим):

прежде всего, я пошел с предложенным методом изменения порядка сортировки как только пользователь нажимает кнопку «сортировка». это означает, что вместо того, чтобы думать об этом с точки зрения «сейчас его сортировка, теперь его нет», я теперь думаю об этом как «данные всегда чем-то сортируются (даже если они« несортированы »)». Я хотел, чтобы «несортированный» список (сортировка по умолчанию) был в том же порядке, что и элементы в базе данных, однако мой ViewModel был настроен таким образом, что я не мог напрямую получить эти исходные элементы базы данных.

для краткости, у меня есть что-то вроде этого:

//inside view model class
val allLists : LiveData<List<UserList>> = repository.getAllLists()

поэтому, когда я хотел использовать сортировку по умолчанию, я подумал о 2 вариантах:

  1. добавить функция в репозитории, которая устанавливает значение getAllLists() для себя, тем самым вызывая наблюдателя, но это не казалось хорошим решением
  2. поддерживать другой список в ViewModel, который является копией тот, который возвращается базой данных, поэтому он всегда будет упорядочен так, как его извлекает база данных (и «сортировка по умолчанию» будет иметь значение этого списка) - но это пустая трата памяти, а также дополнительная сложность (не более того, но все же)

то, что я закончил, это добавление поля created к моему элементу, для которого просто установлено значение System.currentTimeMillis() всякий раз, когда создается экземпляр моего элемента, и используйте th at в качестве моей "сортировки по умолчанию" - очень минимальное добавление кода (даже не полстроки) и совсем не добавило сложности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...