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
Loadingseparately from the final result (ContentorError), and in some cases, we don't want to handleLoadingat 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
Loadingstate as a return type, but isolate its usage inside theonEachStatefunction 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.