A couple of extensions to convert long operations into Flow<Result<T>>
.
Allows handling such operations in functional way and provides single point to handle Pending
, Success
and Failure
states.
Add the dependency:
repositories {
mavenCentral()
}
dependencies {
implementation("com.redmadrobot.gears:resultflow:0.1.0")
}
Use resultFlow
function to turn long operations into Flow<Result<T>>
:
resultFlow { respository.fetchData() }
Use foldEach
to map result value or handle both Success
and Failure
:
resultFlow { respository.fetchData() }
.foldEach(
onSuccess = { handleContent(it) },
onFailure = { showError(it) },
)
// or
resultFlow { repository.fetchData() }
.onEach { handleResult(it) }
Use onEachState
to handle operation state (ResultState) in single place:
resultFlow { repository.fetchData() }
.onEachState { resultState ->
// resultState could be Pending, Success, or Failure
state = state.copy(loading = resultState.isPending)
}
You may notice that the ResultState
is similar to the pattern LCE (Loading, Content, Error).
Both of these patterns allow handling operations in a functional way,
both of them can be used to handle operation state in a single place.
However, these patterns have different purposes.
The ResultState
purpose is to indicate an operation state, ignoring the result of the operation.
So, ResultState.Success
doesn't contain any value compared to LCE's Content.
The result of the operation should be handled separately, using onEach
or foldEach
functions.
Here are more reasons why we don't use LCE:
- In most cases where we've used LCE, it was more convenient to handle
Loading
separately from the final result (Content
orError
), and in some cases, we don't want to handleLoading
at all. For such cases it is handy to have separate places to handle operation state and operation result. - We found it useful to not expose
Loading
state as a return type, but isolate its usage inside theonEachState
function which is called only when we need to handle this state. - We don't always want to handle operations in a functional style.
Especially if we need to call several operations one after another, it is more convenient to do it in an imperative style.
In such cases we use
Result<T>
and it is simple to switch betweenResult<T>
andFlow<Result<T>>
.
Merge requests are welcome. For major changes, open an issue first to discuss what you would like to change.