Thursday, 21 July 2022

Provide domain-layer UseCase classes with HILT

I am implementing some of the architectural designs from Google I/O's app to my own app, but I have come across something in their app that has created some confusion for me.

They have a domain layer with repository usecases, which I use myself in my apps usually. However, I do have to provide these usecases with dagger in my app. But on Google's I/O app, I cannot find any module that provides these usecases. And when used with viewmodels annotated @HiltViewModel (In my own app), it seems like it works? Somehow these get injected into my viewmodels. I do have to provide all the usecase's dependencies(repositories etc) with Hilt, but I don't have to provide any usecase via Hilt.

Here is example how it looks in my code.

Usecase:

abstract class UseCase<in P, R>(private val coroutineDispatcher: CoroutineDispatcher) {

    suspend operator fun invoke(parameters: P): Resource<R> {
        return try {
            withContext(coroutineDispatcher) {
                execute(parameters).let {
                    Resource.Success(it)
                }
            }
        } catch (e: Exception) {
            Timber.d(e)
            Resource.Error(e.toString())
        }
    }

    @Throws(RuntimeException::class)
    protected abstract suspend fun execute(parameters: P): R
}

Concrete implementation of usecase:

class GetListUseCase @Inject constructor(
    private val coroutineDispatcher: CoroutineDispatcher,
    private val remoteRepository: RemoteRepository
): UseCase<ListRequest,ItemsList>(coroutineDispatcher) {

    override suspend fun execute(parameters: ListRequest): ItemsList{
        return remoteRepository.getList(parameters)
    }

}

Viewmodel:

@HiltViewModel
class DetailViewModel @Inject constructor(
    private val GetListUseCase: getListUseCase
): ViewModel() {

    suspend fun getList(): Resource<ItemsList> {
        getPokemonListUseCase.invoke(ListRequest(3))
    }

}

Example of provided repo:

@Singleton
@Provides
fun provideRemoteRepository(
    api: Api
): RemoteRepository = RemoteRepositoryImpl(api)

Remote repo:

@ActivityScoped
class RemoteRepositoryImpl @Inject constructor(
    private val api: Api
): RemoteRepository {

    override suspend fun getList(request: ListRequest): PokemonList {
        return api.getPokemonList(request.limit, request.offset)
    }

}

My Question is: How come this works? Why don't I have to provide usecase' via Hilt? Or is my design wrong and I should provide usecases via Hilt even if this works?

EDIT:

Link to Google I/O domain layer and ui layer if it helps.



from Provide domain-layer UseCase classes with HILT

No comments:

Post a Comment