Coroutines Flow with Dao and generic Result class

Viewed 1980

I have a Dao class which returns List of Car objects as flow.

@Query("SELECT * FROM Car")
fun getAllCars(): Flow<List<Car>>

In my repository, I can use this Dao as follows

fun getAllCars(): Flow<List<Car>>
//Implementation
override fun getAllCars() = carDao.getAllCars()

I can observe this flow in view model and everything works and life was fine.

Now, after reading the post on Developer Android site about

A generic class that contains data and status about loading this data.

I got inspired, so I read one more post here which discuss about having Result class.

So, I have done some changes to repository and I am not able to solve them.

Error:


suspend fun getSomeData(): Flow<Result<List<Car>>> {
        carDao.getAllCars().collect {
            if (it.isNotEmpty()) {
                return flowOf(Result.Success(it))  //<-- Here I am getting error from IDE
            }
            else {
                val throwable = Throwable()
                return flowOf(Result.Failure<List<Car>>(throwable)) //<-- Here I am getting error from IDE
            }
        }
    }

The error is Return is not allowed here and Change to 'return@Collect'

What I want to achieve is:

// At view model side
viewmodelScope.launch {

    repo.getSomeData().collect {
      if (it == Result.Success) {
        //Show data
      }
      else {
        //Show empty screen
      }

    }
}

Is my approach of implementation of Result is wrong? I am not able to figure out what is wrong. Why I can't just return Flow from a flow

2 Answers

If you want to use Result, you should should return Result < YourClass>. It will look like that :

        suspend fun getSomeData(): Result<Flow<List<Car>>> {
            return  carDao.getAllCars().collect {
                if (it.isNotEmpty()) {
                   Result.Success(flowOf(it)) 
                } else {
                   Result.Failure(Throwable())) 
                }
             }
        }

This is what your function should look like. Note there's no need for it to be a suspend fun.

fun getSomeData(): Flow<Result<List<Car>>> = flow {
    carDao.getAllCars().collect {
        if (it.isNotEmpty()) {
            emit(Result.Success(it))
        }
        else {
            emit(Result.Failure<List<Car>>(Throwable()))
        }
    }
}

But what it does is nothing more than adding a mapping step, which you can generalize.

fun <T> Flow<List<T>>.toResultFlow(): Flow<Result<List<T>>> = this.map {
    if (it.isNotEmpty()) Result.Success(it)
    else Result.Failure(Throwable())
}

Related