how can I make Dto map and pass it to the use-case using clean architecture in android kotlin
i tried to make an object class and pass it to the use-case but it didn't work
Note that I will use HILT for dependency injection ... you can use any di library.
You can make a base interface mapper for objects like this:
interface mapper <T,R> {
fun map(t: T): R
}
Then create a class that implements Mapper interface:
class ProductMapper #Inject constructor() : Mapper<RemoteProduct, ProductModel>() {
override fun map(t: RemoteProduct): ProductModel {
// Pass any argument you want or do some business logic
return ProductModel(t.id, t.name)
}
Now I Suggest injecting this ProductMapper inside the repo when you get the response from API or locale database then return mapped data to the use-case.
But anyway you can inject this mapper inside use-case like this:
class GetProductsUseCase #Inject constructor (private val productsMapper: ProductsMapper) {
// Don't forget to inject your repo too
operator fun invoke(): ProductMode {
return productsMapper.map(repo.getProduct())
}
}
Finally using Hilt create new module to bind ProductMapper in our case there is no need to do that step but if your mapper depends on another classes you need to add it in module like this:
#Module
#InstallIn(SingltonComponent::Class)
interface AppModule {
#Binds
fun bindProductDetailsMapper(productsMapper: ProductsMapper): Mapper
}
Related
I was trying to look for similar posts in SO before posting, but most of them talk about retrofit, and my question is about injecting a dependency (Service, Repository or whatever) into an object using #EntryPoint.
I have an object like this:
object FreddieMercuryYouAreTheOne {
lateinit var exception: ExceptionHandler
fun init(appContext: Context) {
setDependencies(appContext)
DoOtherInitStuff...
}
private fun setDependencies(appContext: Context){
val exh = EntryPointAccessors.fromApplication(appContext, Dependencies.ProvideExceptionHandler::class.java)
this.exception = exh.exceptionHandler()
}
/*
* THIS IS JUST AN ABSURD EXAMPLE
* */
private fun DoWhatever(cryptKey16CharStr: String, cryptInitializationVector16CharStr: String) {
try {
doWhatever
}catch(ex: Exception){
exception.logException(ex)
}
}
}
And then I have the class where I set the dependencies:
#Module
#InstallIn(SingletonComponent::class)
class Dependencies {
#EntryPoint
#InstallIn(SingletonComponent::class)
interface ProvideExceptionHandler {
fun exceptionHandler(): ExceptionHandler
}
}
And when building, what I get is the following error:
error: [Dagger/MissingBinding] exception.ExceptionHandler cannot be provided without an #Provides-annotated method.
Well, if I modify my dependencies module as follows:
#Module
#InstallIn(SingletonComponent::class)
class Dependencies {
#Provides
#Singleton
fun bindsExceptionHandler(): ExceptionHandler {
return ExceptionHandler
}
#EntryPoint
#InstallIn(SingletonComponent::class)
interface ProvideExceptionHandler {
fun exceptionHandler(): ExceptionHandler
}
}
Not only build, but it works, and ExceptionHandler is correctly injected in FreddieMercuryYouAreTheOne object, so, as you see, what I have is not exactly an issue, but wondering to know why I need two "providers" to be able to inject a dependency into an object, lets say, why is not enough with interface ProvideExceptionHandler (as Google documentation mentions).
I ask this because I have many class objects across my app, and most of them have dependencies, and so this way I'll have to create two providers for each dependency. Am I doing something wrong?
Entry Points used for field injection for un-supported classes by Hilt like a custom class or content provider.
in your case since you have object FreddieMercuryYouAreTheOne thats can't has a constructer . yeah you need :
1- to Provide the object(instance) you want
in your case:
#Provides
#Singleton
fun bindsExceptionHandler(): ExceptionHandler {
return ExceptionHandler
}
2- and then say hey!! ,i need field injection in my custom class
then you should use :
#EntryPoint
#InstallIn(SingletonComponent::class)
interface ProvideExceptionHandler {
fun exceptionHandler(): ExceptionHandler
}
if you have a normal class you just need to provide the object(just point #1). and then inject it in the constructer.
as i say #EntryPoint for un-supported classes field injection just.
Hint the recommended is constructer-injection over field injection
PLUS: ExceptionHandler and most of dependencies should be injected into ViewModel
I am trying to use Hilt to inject a generic interface implementation but it keep gives me errors
My interface looks like this:
interface Validator<in T> {
fun validate(value: T): Boolean
}
And a typical implementation of it can be like this:
class FullNameValidator #Inject constructor() : Validator<String>{
override fun validate(value: String): Boolean {
val isValid = //Validation logic
return isValid
}
}
Now the way I am trying to use Hilt, i've tried to use #Bind method in a #Module like this
#Binds
abstract fun bindFullNameValidator(validator: FullNameValidator) : Validator<String>
Like i am doing with all interfaces implementations and its working just fine
But here, Hilt claims that it cannot find a way to inject the String object which is the generic type.
Is there a proper way to inject such interface
I have just learnt manual dependency injection, but I am trying out Hilt to handle these dependency injections.
I want to inject a ViewModel into a Fragment. The fragment is contained within an Activity. Right now, I have added the annotations to Application, Activity, and Fragment.
#HiltAndroidApp
class MovieCatalogueApplication : Application()
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
...
}
#AndroidEntryPoint
class HomeFragment : Fragment() {
private lateinit var binding: FragHomeBinding
private val viewmodel: HomeViewModel by viewModels()
...
As can be seen, my HomeFragment depends on HomeViewModel. I have added a ViewModel injection as described here like so.
class HomeViewModel #ViewModelInject constructor(
private val movieRepository: MovieRepository,
private val showRepository: ShowRepository,
#Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
...
}
However, the ViewModel requires two repositories. Right now, my MovieRepository is like so.
class MovieRepository (private val movieApi: MovieService) {
...
}
In the above code, MovieService will be created by Retrofit using the Retrofit.create(class) method. The interface used to create MovieService is like so.
interface MovieService {
...
}
To get my Retrofit instance, I am using the following code.
object RetrofitService {
...
private var _retrofit: Retrofit? = null
val retrofit: Retrofit
get() {
return when (_retrofit) {
null -> {
_retrofit = Retrofit.Builder()
.client(client)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
_retrofit!!
}
else -> _retrofit!!
}
}
}
I am not too sure how I can inject the Retrofit into the Repository to be used by my ViewModel later on. Could someone give me some pointers or step-by-step instructions on how to do this?
Apparently, it is not as hard as it seems.
You have to first define the binding information to Hilt. Binding information tells Hilt how to provide the instances of the dependency specified. Because MovieService is created using a Retrofit (which is a 3rd-party class not created by yourself) using the builder pattern, you can't use the constructor injection and you have to instead use Hilt modules and the annotation #Provides to tell Hilt about this binding information.
As described in the doc, the annotated function in the Hilt module you have created will supply the following information to Hilt so that Hilt can provide the instances of the dependency.
• The function return type tells Hilt what type the function provides instances of.
• The function parameters tell Hilt the dependencies of the corresponding type.
• The function body tells Hilt how to provide an instance of the corresponding type. Hilt executes the function body every time it needs to provide an instance of that type.
In the end, you only need to modify the MovieRepository class, add a module for each repository, and annotate the function that tells Hilt how to provide the service instance created with Retrofit with #Provides.
Code.
class MovieRepository #Inject constructor(
private val movieApi: MovieService
) {
...
}
interface MovieService {
...
}
#Module
#InstallIn(ActivityRetainedComponent::class)
object MovieModule {
#Provides
fun provideMovieService(): MovieService
= RetrofitService.retrofit.create(MovieService::class.java)
}
As you can see, the ActivityRetainedComponent is referred in the #InstallIn annotation because the Repository is to be injected to a ViewModel. Each Android component is associated to different Hilt components.
I'm new to DI and Dagger.
I have this dependency graph in the Android project:
#Module(includes=[Module1, Module2, Module3]) ClassAModule
#Module(includes=[classAModule, Module4]) ClassBModule
#Module(includes=[ClassBModule]) ClassCModule
#Module(includes=[ClassBModule]) ClassDModule
Here's how Module3 looks like
#Module
class Module3 {
#Provides
fun provideUrl(): Url{
return ...
}
}
Module3's Url is required by ClassAModule,
But I want ClassCModule and ClassDModule to be able to provide different Url to ClassAModule
how should I approach this?
To get specific url for any module, you need to define annotation on provider method.
Example
#Provides
#Room
fun provideRoomWordDataSource(): WordDataSource {
return RoomWordDataSource()
}
#Provides
#Firestore
fun provideFirestoreWordDataSource(): WordDataSource {
return FirestoreWordDataSource()
}
#Singleton
class WordRepository
#Inject constructor(
#Room private val room: WordDataSource,
#Firestore private val firestore: WordDataSource
) : Repository<String, Word>(rx, rm), WordDataSource {
}
First two provider method has define WordDataSource instance of two difference class and define with two different annotation #Room and #Firestore.
To get two different WordDataSource in WordRepository, have just used #Room and #Firestore annotation in its constructor.
Enjoy the annotation power in Dagger. :)
Please feel free, if you need more details from me.
How do we inject ViewModel with dependency using Koin?
So For Example I have a ViewModel thats like this:
class SomeViewModel(val someDependency: SomeDependency, val anotherDependency: AnotherDependency): ViewModel()
Now the official docs here, states that to provide a ViewModel we could do something like:
val myModule : Module = applicationContext {
// ViewModel instance of MyViewModel
// get() will resolve Repository instance
viewModel { SomeViewModel(get(), get()) }
// Single instance of SomeDependency
single<SomeDependency> { SomeDependency() }
// Single instance of AnotherDependency
single<AnotherDependency> { AnotherDependency() }
}
Then to inject it, we can do something like:
class MyActivity : AppCompatActivity(){
// Lazy inject SomeViewModel
val model : SomeViewModel by viewModel()
override fun onCreate() {
super.onCreate()
// or also direct retrieve instance
val model : SomeViewModel= getViewModel()
}
}
The confusing part for me is that, normally you will need a ViewModelFactory to provide the ViewModel with Dependencies. Where is the ViewModelFactory here? is it no longer needed?
Hello viewmodel() it's a Domain Specific Language (DSL) keywords that help creating a ViewModel instance.
At this [link][1] of official documentation you can find more info
The viewModel keyword helps declaring a factory instance of ViewModel.
This instance will be handled by internal ViewModelFactory and
reattach ViewModel instance if needed.
this example of koin version 2.0 [1]: https://insert-koin.io/docs/2.0/documentation/koin-android/index.html#_viewmodel_dsl
// Given some classes
class Controller(val service : BusinessService)
class BusinessService()
// just declare it
val myModule = module {
single { Controller(get()) }
single { BusinessService() }
}