Skip to content

Commit 362f143

Browse files
committed
Adds Saved State to TasksVM
1 parent 313b2bd commit 362f143

File tree

5 files changed

+58
-33
lines changed

5 files changed

+58
-33
lines changed

app/src/main/java/com/example/android/architecture/blueprints/todoapp/ViewModelFactory.kt

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
*/
1616
package com.example.android.architecture.blueprints.todoapp
1717

18+
import android.app.Application
19+
import android.os.Bundle
20+
import androidx.lifecycle.AbstractSavedStateViewModelFactory
21+
import androidx.lifecycle.SavedStateHandle
22+
import androidx.lifecycle.SavedStateViewModelFactory
1823
import androidx.lifecycle.ViewModel
1924
import androidx.lifecycle.ViewModelProvider
25+
import androidx.savedstate.SavedStateRegistryOwner
2026
import com.example.android.architecture.blueprints.todoapp.addedittask.AddEditTaskViewModel
2127
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository
2228
import com.example.android.architecture.blueprints.todoapp.statistics.StatisticsViewModel
@@ -28,22 +34,27 @@ import com.example.android.architecture.blueprints.todoapp.tasks.TasksViewModel
2834
*/
2935
@Suppress("UNCHECKED_CAST")
3036
class ViewModelFactory constructor(
31-
private val tasksRepository: TasksRepository
32-
) : ViewModelProvider.NewInstanceFactory() {
37+
private val tasksRepository: TasksRepository,
38+
owner: SavedStateRegistryOwner,
39+
defaultArgs: Bundle? = null
40+
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
3341

34-
override fun <T : ViewModel> create(modelClass: Class<T>) =
35-
with(modelClass) {
36-
when {
37-
isAssignableFrom(StatisticsViewModel::class.java) ->
38-
StatisticsViewModel(tasksRepository)
39-
isAssignableFrom(TaskDetailViewModel::class.java) ->
40-
TaskDetailViewModel(tasksRepository)
41-
isAssignableFrom(AddEditTaskViewModel::class.java) ->
42-
AddEditTaskViewModel(tasksRepository)
43-
isAssignableFrom(TasksViewModel::class.java) ->
44-
TasksViewModel(tasksRepository)
45-
else ->
46-
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
47-
}
48-
} as T
42+
override fun <T : ViewModel> create(
43+
key: String,
44+
modelClass: Class<T>,
45+
handle: SavedStateHandle
46+
) = with(modelClass) {
47+
when {
48+
isAssignableFrom(StatisticsViewModel::class.java) ->
49+
StatisticsViewModel(tasksRepository)
50+
isAssignableFrom(TaskDetailViewModel::class.java) ->
51+
TaskDetailViewModel(tasksRepository)
52+
isAssignableFrom(AddEditTaskViewModel::class.java) ->
53+
AddEditTaskViewModel(tasksRepository)
54+
isAssignableFrom(TasksViewModel::class.java) ->
55+
TasksViewModel(tasksRepository, handle)
56+
else ->
57+
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
58+
}
59+
} as T
4960
}

app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import androidx.annotation.DrawableRes
1919
import androidx.annotation.StringRes
2020
import androidx.lifecycle.LiveData
2121
import androidx.lifecycle.MutableLiveData
22+
import androidx.lifecycle.SavedStateHandle
2223
import androidx.lifecycle.Transformations
2324
import androidx.lifecycle.ViewModel
25+
import androidx.lifecycle.distinctUntilChanged
2426
import androidx.lifecycle.switchMap
2527
import androidx.lifecycle.viewModelScope
2628
import com.example.android.architecture.blueprints.todoapp.Event
@@ -30,13 +32,15 @@ import com.example.android.architecture.blueprints.todoapp.data.Result.Success
3032
import com.example.android.architecture.blueprints.todoapp.data.Task
3133
import com.example.android.architecture.blueprints.todoapp.data.source.TasksDataSource
3234
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository
35+
import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType.*
3336
import kotlinx.coroutines.launch
3437

3538
/**
3639
* ViewModel for the task list screen.
3740
*/
3841
class TasksViewModel(
39-
private val tasksRepository: TasksRepository
42+
private val tasksRepository: TasksRepository,
43+
private val savedStateHandle: SavedStateHandle
4044
) : ViewModel() {
4145

4246
private val _forceUpdate = MutableLiveData<Boolean>(false)
@@ -49,7 +53,7 @@ class TasksViewModel(
4953
_dataLoading.value = false
5054
}
5155
}
52-
tasksRepository.observeTasks().switchMap { filterTasks(it) }
56+
tasksRepository.observeTasks().distinctUntilChanged().switchMap { filterTasks(it) }
5357
}
5458

5559
val items: LiveData<List<Task>> = _items
@@ -72,8 +76,6 @@ class TasksViewModel(
7276
private val _snackbarText = MutableLiveData<Event<Int>>()
7377
val snackbarText: LiveData<Event<Int>> = _snackbarText
7478

75-
private var currentFiltering = TasksFilterType.ALL_TASKS
76-
7779
// Not used at the moment
7880
private val isDataLoadingError = MutableLiveData<Boolean>()
7981

@@ -92,7 +94,7 @@ class TasksViewModel(
9294

9395
init {
9496
// Set initial state
95-
setFiltering(TasksFilterType.ALL_TASKS)
97+
setFiltering(getSavedFilterType())
9698
loadTasks(true)
9799
}
98100

@@ -104,23 +106,23 @@ class TasksViewModel(
104106
* [TasksFilterType.ACTIVE_TASKS]
105107
*/
106108
fun setFiltering(requestType: TasksFilterType) {
107-
currentFiltering = requestType
109+
savedStateHandle.set(TASKS_FILTER_SAVED_STATE_KEY, requestType.ordinal)
108110

109111
// Depending on the filter type, set the filtering label, icon drawables, etc.
110112
when (requestType) {
111-
TasksFilterType.ALL_TASKS -> {
113+
ALL_TASKS -> {
112114
setFilter(
113115
R.string.label_all, R.string.no_tasks_all,
114116
R.drawable.logo_no_fill, true
115117
)
116118
}
117-
TasksFilterType.ACTIVE_TASKS -> {
119+
ACTIVE_TASKS -> {
118120
setFilter(
119121
R.string.label_active, R.string.no_tasks_active,
120122
R.drawable.ic_check_circle_96dp, false
121123
)
122124
}
123-
TasksFilterType.COMPLETED_TASKS -> {
125+
COMPLETED_TASKS -> {
124126
setFilter(
125127
R.string.label_completed, R.string.no_tasks_completed,
126128
R.drawable.ic_verified_user_96dp, false
@@ -195,7 +197,7 @@ class TasksViewModel(
195197
if (tasksResult is Success) {
196198
isDataLoadingError.value = false
197199
viewModelScope.launch {
198-
result.value = filterItems(tasksResult.data, currentFiltering)
200+
result.value = filterItems(tasksResult.data, getSavedFilterType())
199201
}
200202
} else {
201203
result.value = emptyList()
@@ -218,11 +220,11 @@ class TasksViewModel(
218220
// We filter the tasks based on the requestType
219221
for (task in tasks) {
220222
when (filteringType) {
221-
TasksFilterType.ALL_TASKS -> tasksToShow.add(task)
222-
TasksFilterType.ACTIVE_TASKS -> if (task.isActive) {
223+
ALL_TASKS -> tasksToShow.add(task)
224+
ACTIVE_TASKS -> if (task.isActive) {
223225
tasksToShow.add(task)
224226
}
225-
TasksFilterType.COMPLETED_TASKS -> if (task.isCompleted) {
227+
COMPLETED_TASKS -> if (task.isCompleted) {
226228
tasksToShow.add(task)
227229
}
228230
}
@@ -233,4 +235,12 @@ class TasksViewModel(
233235
fun refresh() {
234236
_forceUpdate.value = true
235237
}
238+
239+
private fun getSavedFilterType() : TasksFilterType {
240+
return TasksFilterType
241+
.values()[savedStateHandle.get(TASKS_FILTER_SAVED_STATE_KEY) ?: ALL_TASKS.ordinal]
242+
}
236243
}
244+
245+
// Used to save the current filtering in SavedStateHandle.
246+
const val TASKS_FILTER_SAVED_STATE_KEY = "TASKS_FILTER_SAVED_STATE_KEY"

app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/FragmentExt.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ import com.example.android.architecture.blueprints.todoapp.ViewModelFactory
2525

2626
fun Fragment.getViewModelFactory(): ViewModelFactory {
2727
val repository = (requireContext().applicationContext as TodoApplication).taskRepository
28-
return ViewModelFactory(repository)
28+
return ViewModelFactory(repository, this)
2929
}

app/src/prod/java/com/example/android/architecture/blueprints/todoapp/ServiceLocator.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ object ServiceLocator {
4646
}
4747

4848
private fun createTasksRepository(context: Context): TasksRepository {
49-
val newRepo = DefaultTasksRepository(TasksRemoteDataSource, createTaskLocalDataSource(context))
49+
val newRepo =
50+
DefaultTasksRepository(TasksRemoteDataSource, createTaskLocalDataSource(context))
5051
tasksRepository = newRepo
5152
return newRepo
5253
}
@@ -59,7 +60,7 @@ object ServiceLocator {
5960
private fun createDataBase(context: Context): ToDoDatabase {
6061
val result = Room.databaseBuilder(
6162
context.applicationContext,
62-
ToDoDatabase::class.java, "Tasks.db"
63+
ToDoDatabase::class.java, DB_NAME
6364
).build()
6465
database = result
6566
return result
@@ -81,3 +82,5 @@ object ServiceLocator {
8182
}
8283
}
8384
}
85+
86+
private const val DB_NAME = "Tasks.db"

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ android.enableJetifier=true
2020
android.useAndroidX=true
2121
android.enableUnitTestBinaryResources=true
2222
android.enableR8=true
23+
kapt.incremental.apt=true

0 commit comments

Comments
 (0)