Skip to content

Commit a3d0c07

Browse files
authored
Replace Result with exception handling (#906)
1 parent ce5fe06 commit a3d0c07

File tree

22 files changed

+203
-335
lines changed

22 files changed

+203
-335
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import androidx.lifecycle.ViewModel
2121
import androidx.lifecycle.viewModelScope
2222
import com.example.android.architecture.blueprints.todoapp.R
2323
import com.example.android.architecture.blueprints.todoapp.TodoDestinationsArgs
24-
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
2524
import com.example.android.architecture.blueprints.todoapp.data.Task
2625
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository
2726
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -132,9 +131,8 @@ class AddEditTaskViewModel @Inject constructor(
132131
it.copy(isLoading = true)
133132
}
134133
viewModelScope.launch {
135-
tasksRepository.getTask(taskId).let { result ->
136-
if (result is Success) {
137-
val task = result.data
134+
tasksRepository.getTask(taskId).let { task ->
135+
if (task != null) {
138136
_uiState.update {
139137
it.copy(
140138
title = task.title,

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

Lines changed: 0 additions & 42 deletions
This file was deleted.

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/DefaultTasksRepository.kt

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package com.example.android.architecture.blueprints.todoapp.data.source
1818

19-
import com.example.android.architecture.blueprints.todoapp.data.Result
20-
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
2119
import com.example.android.architecture.blueprints.todoapp.data.Task
2220
import kotlinx.coroutines.CoroutineDispatcher
2321
import kotlinx.coroutines.Dispatchers
@@ -35,13 +33,9 @@ class DefaultTasksRepository(
3533
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
3634
) : TasksRepository {
3735

38-
override suspend fun getTasks(forceUpdate: Boolean): Result<List<Task>> {
36+
override suspend fun getTasks(forceUpdate: Boolean): List<Task> {
3937
if (forceUpdate) {
40-
try {
41-
updateTasksFromRemoteDataSource()
42-
} catch (ex: Exception) {
43-
return Result.Error(ex)
44-
}
38+
updateTasksFromRemoteDataSource()
4539
}
4640
return tasksLocalDataSource.getTasks()
4741
}
@@ -50,7 +44,7 @@ class DefaultTasksRepository(
5044
updateTasksFromRemoteDataSource()
5145
}
5246

53-
override fun getTasksStream(): Flow<Result<List<Task>>> {
47+
override fun getTasksStream(): Flow<List<Task>> {
5448
return tasksLocalDataSource.getTasksStream()
5549
}
5650

@@ -61,33 +55,35 @@ class DefaultTasksRepository(
6155
private suspend fun updateTasksFromRemoteDataSource() {
6256
val remoteTasks = tasksRemoteDataSource.getTasks()
6357

64-
if (remoteTasks is Success) {
65-
// Real apps might want to do a proper sync, deleting, modifying or adding each task.
66-
tasksLocalDataSource.deleteAllTasks()
67-
remoteTasks.data.forEach { task ->
68-
tasksLocalDataSource.saveTask(task)
69-
}
70-
} else if (remoteTasks is Result.Error) {
71-
throw remoteTasks.exception
58+
// Real apps might want to do a proper sync, deleting, modifying or adding each task.
59+
tasksLocalDataSource.deleteAllTasks()
60+
remoteTasks.forEach { task ->
61+
tasksLocalDataSource.saveTask(task)
7262
}
7363
}
7464

75-
override fun getTaskStream(taskId: String): Flow<Result<Task>> {
65+
override fun getTaskStream(taskId: String): Flow<Task?> {
7666
return tasksLocalDataSource.getTaskStream(taskId)
7767
}
7868

7969
private suspend fun updateTaskFromRemoteDataSource(taskId: String) {
8070
val remoteTask = tasksRemoteDataSource.getTask(taskId)
8171

82-
if (remoteTask is Success) {
83-
tasksLocalDataSource.saveTask(remoteTask.data)
72+
if (remoteTask == null) {
73+
tasksLocalDataSource.deleteTask(taskId)
74+
} else {
75+
tasksLocalDataSource.saveTask(remoteTask)
8476
}
8577
}
8678

8779
/**
88-
* Relies on [getTasks] to fetch data and picks the task with the same ID.
80+
* Relies on [getTasks] to fetch data and picks the task with the same ID. Will return a null
81+
* Task if the task cannot be found.
82+
*
83+
* @param taskId - The ID of the task
84+
* @param forceUpdate - true if the task should be updated from the remote data source.
8985
*/
90-
override suspend fun getTask(taskId: String, forceUpdate: Boolean): Result<Task> {
86+
override suspend fun getTask(taskId: String, forceUpdate: Boolean): Task? {
9187
if (forceUpdate) {
9288
updateTaskFromRemoteDataSource(taskId)
9389
}
@@ -110,9 +106,7 @@ class DefaultTasksRepository(
110106

111107
override suspend fun completeTask(taskId: String) {
112108
withContext(ioDispatcher) {
113-
(getTaskWithId(taskId) as? Success)?.let { it ->
114-
completeTask(it.data)
115-
}
109+
getTaskWithId(taskId)?.let { completeTask(it) }
116110
}
117111
}
118112

@@ -125,9 +119,7 @@ class DefaultTasksRepository(
125119

126120
override suspend fun activateTask(taskId: String) {
127121
withContext(ioDispatcher) {
128-
(getTaskWithId(taskId) as? Success)?.let { it ->
129-
activateTask(it.data)
130-
}
122+
getTaskWithId(taskId)?.let { activateTask(it) }
131123
}
132124
}
133125

@@ -154,7 +146,7 @@ class DefaultTasksRepository(
154146
}
155147
}
156148

157-
private suspend fun getTaskWithId(id: String): Result<Task> {
149+
private suspend fun getTaskWithId(id: String): Task? {
158150
return tasksLocalDataSource.getTask(id)
159151
}
160152
}

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/TasksDataSource.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.example.android.architecture.blueprints.todoapp.data.source
1818

19-
import com.example.android.architecture.blueprints.todoapp.data.Result
2019
import com.example.android.architecture.blueprints.todoapp.data.Task
2120
import kotlinx.coroutines.flow.Flow
2221

@@ -25,15 +24,15 @@ import kotlinx.coroutines.flow.Flow
2524
*/
2625
interface TasksDataSource {
2726

28-
fun getTasksStream(): Flow<Result<List<Task>>>
27+
fun getTasksStream(): Flow<List<Task>>
2928

30-
suspend fun getTasks(): Result<List<Task>>
29+
suspend fun getTasks(): List<Task>
3130

3231
suspend fun refreshTasks()
3332

34-
fun getTaskStream(taskId: String): Flow<Result<Task>>
33+
fun getTaskStream(taskId: String): Flow<Task?>
3534

36-
suspend fun getTask(taskId: String): Result<Task>
35+
suspend fun getTask(taskId: String): Task?
3736

3837
suspend fun refreshTask(taskId: String)
3938

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/TasksRepository.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.example.android.architecture.blueprints.todoapp.data.source
1818

19-
import com.example.android.architecture.blueprints.todoapp.data.Result
2019
import com.example.android.architecture.blueprints.todoapp.data.Task
2120
import kotlinx.coroutines.flow.Flow
2221

@@ -25,15 +24,15 @@ import kotlinx.coroutines.flow.Flow
2524
*/
2625
interface TasksRepository {
2726

28-
fun getTasksStream(): Flow<Result<List<Task>>>
27+
fun getTasksStream(): Flow<List<Task>>
2928

30-
suspend fun getTasks(forceUpdate: Boolean = false): Result<List<Task>>
29+
suspend fun getTasks(forceUpdate: Boolean = false): List<Task>
3130

3231
suspend fun refreshTasks()
3332

34-
fun getTaskStream(taskId: String): Flow<Result<Task>>
33+
fun getTaskStream(taskId: String): Flow<Task?>
3534

36-
suspend fun getTask(taskId: String, forceUpdate: Boolean = false): Result<Task>
35+
suspend fun getTask(taskId: String, forceUpdate: Boolean = false): Task?
3736

3837
suspend fun refreshTask(taskId: String)
3938

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/local/TasksLocalDataSource.kt

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@
1616

1717
package com.example.android.architecture.blueprints.todoapp.data.source.local
1818

19-
import com.example.android.architecture.blueprints.todoapp.data.Result
20-
import com.example.android.architecture.blueprints.todoapp.data.Result.Error
21-
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
2219
import com.example.android.architecture.blueprints.todoapp.data.Task
2320
import com.example.android.architecture.blueprints.todoapp.data.source.TasksDataSource
2421
import kotlinx.coroutines.CoroutineDispatcher
2522
import kotlinx.coroutines.Dispatchers
26-
import kotlinx.coroutines.flow.Flow
27-
import kotlinx.coroutines.flow.map
2823
import kotlinx.coroutines.withContext
2924

3025
/**
@@ -35,17 +30,9 @@ class TasksLocalDataSource internal constructor(
3530
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
3631
) : TasksDataSource {
3732

38-
override fun getTasksStream(): Flow<Result<List<Task>>> {
39-
return tasksDao.observeTasks().map {
40-
Success(it)
41-
}
42-
}
33+
override fun getTasksStream() = tasksDao.observeTasks()
4334

44-
override fun getTaskStream(taskId: String): Flow<Result<Task>> {
45-
return tasksDao.observeTaskById(taskId).map {
46-
Success(it)
47-
}
48-
}
35+
override fun getTaskStream(taskId: String) = tasksDao.observeTaskById(taskId)
4936

5037
override suspend fun refreshTask(taskId: String) {
5138
// NO-OP
@@ -55,25 +42,12 @@ class TasksLocalDataSource internal constructor(
5542
// NO-OP
5643
}
5744

58-
override suspend fun getTasks(): Result<List<Task>> = withContext(ioDispatcher) {
59-
return@withContext try {
60-
Success(tasksDao.getTasks())
61-
} catch (e: Exception) {
62-
Error(e)
63-
}
45+
override suspend fun getTasks(): List<Task> = withContext(ioDispatcher) {
46+
return@withContext tasksDao.getTasks()
6447
}
6548

66-
override suspend fun getTask(taskId: String): Result<Task> = withContext(ioDispatcher) {
67-
try {
68-
val task = tasksDao.getTaskById(taskId)
69-
if (task != null) {
70-
return@withContext Success(task)
71-
} else {
72-
return@withContext Error(Exception("Task not found!"))
73-
}
74-
} catch (e: Exception) {
75-
return@withContext Error(e)
76-
}
49+
override suspend fun getTask(taskId: String): Task? = withContext(ioDispatcher) {
50+
return@withContext tasksDao.getTaskById(taskId)
7751
}
7852

7953
override suspend fun saveTask(task: Task) = withContext(ioDispatcher) {

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/remote/TasksRemoteDataSource.kt

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616

1717
package com.example.android.architecture.blueprints.todoapp.data.source.remote
1818

19-
import com.example.android.architecture.blueprints.todoapp.data.Result
20-
import com.example.android.architecture.blueprints.todoapp.data.Result.Error
21-
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
2219
import com.example.android.architecture.blueprints.todoapp.data.Task
2320
import com.example.android.architecture.blueprints.todoapp.data.source.TasksDataSource
2421
import kotlinx.coroutines.delay
@@ -47,41 +44,31 @@ object TasksRemoteDataSource : TasksDataSource {
4744
observableTasks.value = getTasks()
4845
}
4946

50-
override fun getTaskStream(taskId: String): Flow<Result<Task>> {
47+
override fun getTaskStream(taskId: String): Flow<Task?> {
5148
return observableTasks.map { tasks ->
52-
when (tasks) {
53-
is Error -> Error(tasks.exception)
54-
is Success -> {
55-
val task = tasks.data.firstOrNull() { it.id == taskId }
56-
?: return@map Error(Exception("Not found"))
57-
Success(task)
58-
}
59-
}
49+
tasks.firstOrNull { it.id == taskId }
6050
}
6151
}
6252

6353
override suspend fun refreshTask(taskId: String) {
6454
refreshTasks()
6555
}
6656

67-
override fun getTasksStream(): Flow<Result<List<Task>>> {
57+
override fun getTasksStream(): Flow<List<Task>> {
6858
return observableTasks
6959
}
7060

71-
override suspend fun getTasks(): Result<List<Task>> {
61+
override suspend fun getTasks(): List<Task> {
7262
// Simulate network by delaying the execution.
7363
val tasks = TASKS_SERVICE_DATA.values.toList()
7464
delay(SERVICE_LATENCY_IN_MILLIS)
75-
return Success(tasks)
65+
return tasks
7666
}
7767

78-
override suspend fun getTask(taskId: String): Result<Task> {
68+
override suspend fun getTask(taskId: String): Task? {
7969
// Simulate network by delaying the execution.
8070
delay(SERVICE_LATENCY_IN_MILLIS)
81-
TASKS_SERVICE_DATA[taskId]?.let {
82-
return Success(it)
83-
}
84-
return Error(Exception("Task not found"))
71+
return TASKS_SERVICE_DATA[taskId]
8572
}
8673

8774
private fun addTask(title: String, description: String) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import com.example.android.architecture.blueprints.todoapp.data.Task
2121
/**
2222
* Function that does some trivial computation. Used to showcase unit tests.
2323
*/
24-
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {
24+
internal fun getActiveAndCompletedStats(tasks: List<Task>): StatsResult {
2525

26-
return if (tasks == null || tasks.isEmpty()) {
26+
return if (tasks.isEmpty()) {
2727
StatsResult(0f, 0f)
2828
} else {
2929
val totalTasks = tasks.size

0 commit comments

Comments
 (0)