I am writing a simple to-do list style app for android and I am having problems with adding sorting functionality.
I have a screen with a RecyclerView
showing all lists that belong to the user, and I would like to add a functionality which allows the user to turn sorting on or off. The problem is that I cant seem to find a way to make the list displayed to the user stay consistently sorted after another change is made.
Lets say the lists are held in a Room
database.
The easiest and most consistent way to achieve what I want is to sort the data in the database itself, but this is probably not the way to go as it would be complicated to implement (if even possible).
Most likely I should sort the data locally in my view model. I figured I could do this using MediatorLiveData
which will observe the database while is itself observed by the host activity. Before updating the MediatorLiveData
, I would sort the list using a flag isSorting
to either return the data as-is or sort it before delivering the result.
The key to my question is that I want to be able to turn this functionality on and off, while still maintaining the order of the data afterwards (when another operation is performed). Here is an example of a typical events flow:
- User opens the app and the database returns: "list 3", "list 1", "list 2".
- The data is displayed to the user as-is (unsorted)
- The user turns on the sorting feature
- The view model sorts the backing list locally
- The observer in the activity receives the sorted list
- The activity now shows "list 1", "list 2", "list 3"
- The user adds a new list: "list 4".
Before I get to the problem part, here is some code:
Repository (shortened for brevity):
class ListsRepository {
val db = Database().getInstance();
fun getAllUserLists(userId: Int): LiveData<List<UserList>>
}
Activity (shortened for brevity):
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 (shortened for brevity)
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
}
}
}
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"
What happens now is:
- The
MediatorLiveData
receives the update from the database as "list 3","list 1","list 2","list 4","list 0" (the original order of the database, plus the new lists) - The
isSorting
flag is off, so it sets the value to the returned data as-is - The data is displayed to the user unsorted, but the previous sorting is now lost
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).
I hope I made myself clear. Is this possible to achieve without adding too much complexity? What is the "standard way" to provide sorting functionality in an android app?
Thanks