Resource
Resource is a sealed class that allows you to wrap any object based on a state. It has these options:
-
๐ Loading: To use at that moment that a loading indicator should appear. -
๐ Success: When the happy path occurs. -
โ Error: If there is a problem you will get this.
This library works very well when used in conjunction with NetworkResponse which is very similar to Resource but is intended for use with Retrofit.
For more information see the website
Download
This library is Kotlin Multiplatform but at this moment jvm is the only artifact generated. It is available at Maven Central.
implementation("com.javiersc.resource:resource:$version")
Fold your Resource
Fold a Resource invokes multiple callbacks to manage its state for any event. A normal flow can be:
- Emit
Loadingto show the progress indicator. - Emit
Successto populate your data or emitErrorif something were wrong to show an error.
val dog: Dog = Dog("Auri")
val resource: Resource<Dog, Error> = Resource.Success(dog)
resource.folder {
loading { println("Loading: Yes") }
noLoading { println("Loading: no") } // Invoked
success { dog: Dog -> println("Success: $dog") } // Invoked
noSuccess { println("Success: no") }
error { error: Error -> println("Error: $error") }
noError { println("Error: no") } // Invoked
}
Exists a fold function similar to folder buth without the builder pattern
val dog: Dog = Dog("Auri")
val resource: Resource<Dog, Error> = Resource.Success(dog)
resource.fold(
loading = { println("Loading: Yes") },
noLoading = { println("Loading: no") }, // Invoked
success = { dog: Dog -> println("Success: $dog") }, // Invoked
noSuccess = { println("Success: no") },
error = { error: Error -> println("Error: $error") },
noError = { println("Error: no") }, // Invoked
)
You don't have to add all those functions, for example, you usually only have to use:
loadingto show a progress indicator.noLoadingto hide the progress indicator.successto load the data.errorto show and error.
Mappers and common extension functions
Map a Resource to another Resource is possible with the following extension function:
ResourcetoResource
val anotherResource: Resource<AnotherUser, AnotherError> = resource.map(
success = { user: User -> user.toAnotherUser() },
error = { error: Error -> error.toAnotherError() }
)
// toAnotherUser() and toAnotherError() mappers should be created by yourself, if they are
// extension functions and the resource uses inference for the type:
val anotherResource = resource.map(User::toAnotherUser, Error::toAnotherError)
- Some value to
Resource
val name: String = "Auri"
val nameResource = name.toResourceSuccess()
val message: String = "Some error message"
val messageResource = message.toResourceError()
- A lot of checkers for each state, for example:
val resource: Resource<String> = Resource.Success("Auri")
resource.ifSuccess { data: String ->
println(data) // "Auri"
}
You can see all the common extension functions here and here
Flow
There are four Flow extension functions:
Flow<R>.map(...)included in Kotlin, let you to easily map the object inside yourFlowto anyResource:
val usersFlow: Flow<List<User>>
val usersResourceFlow: Flow<Resource<List<User>, Error>> =
usersFlow.map { users: List<User> -> Resource.Success(users) }
Flow<R>.toResourceSuccess()
val usersSuccessFlow: Flow<Resource<List<User>, Error>> = usersFlow.toResourceSuccess()
Flow<R>.toResourceError()
val usersErrorFlow: Flow<Resource<List<User>, Error>> = usersFlow.toResourceError()