Is a Kotlin multiplatform mobile library that helps you with
abstraction of Usecase as a component from clean architecture.
Its main objective is separation of concerns and better domain modeling.
It is backed by Kotlinx Coroutines
- delegate work to background thread
- cancel on reexecution (optional)
- error handling
- auto-cancel of coroutine context
Library contains two main parts UseCase
and FlowUseCase
.
UseCase
is for events that return single response. (e.g. REST API call GET, POST...)FlowUseCase
is for events that return multiple responses. (e.g. Location data updates...)
UseCase same as FlowUseCase has two generic parameters. The first is argument type, the second specify return type.
If you don't need any of these, just put Unit
in there.
When creating a usecase, don't forget to freeze()
it in init block, but after local parameters initialization.
If you use DI, inject before freezing, or you will end up with InvalidMutabilityException
. This step won't be necessary
after release of New Native Memory Model. You can preview it with Kotlin 1.6.0-M1.
// Common
class GetCoinsListUseCase : UseCase<Unit, List<Coin>>() {
private val coinStore: CoinStore = CoinStore(RestApiManager, DatabaseManager)
init {
freeze()
}
override suspend fun build(arg: Unit): List<Coin> {
return coinStore.fetchCoins().coins.map {
Coin(
it.id,
it.name,
it.icon,
it.symbol,
it.price
)
}
}
}
You can execute the Usecase anywhere you want, but you have to implement the CoroutineScopeOwner
interface and specify the coroutineContext
where the Usecase will be executed.
So the ViewModel
is the most common option.
// Android
class CoinsViewModel : ViewModel(), CoroutineScopeOwner {
override val coroutineScope: CoroutineScope
get() = viewModelScope
private val getCoinsUseCase = GetCoinsListUseCase()
var coins by mutableStateOf(emptyList<Coin>())
fun fetchCoins() {
getCoinsUseCase.execute(Unit) {
onSuccess { coins = it.list }
onError { print(it.message) }
}
}
}
As the Swift language also features closing lambdas, you can execute the Usecase nearly in the same fashion as on Android.
// iOS
class CoinsViewModel : BaseViewModel, ObservableObject {
@Published var coins = [Coin]()
private let getCoinsUseCase = GetCoinsListUseCase()
func getCoins() {
getCoinsUseCase.execute(self, args: KotlinUnit()) {
$0.onNext { list in
guard let coinsList = list?.list else { return }
self.coins = coinsList as [Coin]
}
$0.onError { error in
print(error)
}
}
}
}
Check out the full example in my other project the KMM Template