If Adapter have an interface like clickListener, Fragment implement that interface and Fragment pass the instance of interface in constructor to the adapter, How to inject adapter with hilt?
How to solve this issue?
Here is the error
error: [Dagger/MissingBinding] ... cannot be provided without an #Inject constructor or an #Provides-annotated method. This type supports members injection but cannot be implicitly provided.
#AndroidEntryPoint
class HomeFragment: Fragment(), ShowsAdapter.Interaction {
#Inject
lateinit var adapter: ShowsAdapter
private val viewModel: HomeViewModel by hiltNavGraphViewModels(R.id.my_nav)
....
}
class ShowsAdapter #Inject constructor(private val interaction: Interaction) :
RecyclerView.Adapter<ShowsAdapter.ShowsHolder>() {
....
interface Interaction {
fun onItemSelected(show: Show)
}
}
#Module
#InstallIn(FragmentComponent::class)
abstract class HomeModule {
#Binds
abstract fun provideInteraction(homeFragment: HomeFragment): ShowsAdapter.Interaction
}
Related
I am having a problem that I need inject an instance of repository class into Application class which is provided by Module (Installed in ViewModelComponent, and provide function marked with #ViewModelScope annotation)
Repository
interface IARepository
class ARepository #Inject constructor() : IARepository
Module
#Module
#InstallIn(ViewModelComponent::class)
interface RepositoryModule {
#Binds
#ViewModelScoped
fun provideARepos(impl: ARepository): IARepository
}
ViewModel
#HiltViewModel
class TestViewModel #Inject constructor(
private val useCase1: UseCase1,
private val useCase2: UseCase2,
) {
...
}
Two UseCase1 and UseCase2 are using IARepository, since if I provides IARepository with ViewModelScope, two instance useCase1 and useCase2 will be using the same instance of repository.
It worked until I inject repository into Application (singleton things)
Application
#HiltAndroidApp
class TestApplication : Application() {
#Inject
lateinit var a: IARepository
}
After that I got error
[Dagger/MissingBinding] IARepository cannot be provided without an #Provides-annotated method.
public abstract static class SingletonC implements FragmentGetContextFix.FragmentGetContextFixEntryPoint
Application_HiltComponents.java:129: error: [Dagger/MissingBinding] ...core.domain.IARepository cannot be provided without an #Provides-annotated method.
public abstract static class SingletonC implements FragmentGetContextFix.FragmentGetContextFixEntryPoint,
^
A binding for ....core.domain.IARepository exists in ...Application_HiltComponents.ViewModelC:
....core.domain.IARepository is injected at
[...Application_HiltComponents.SingletonC] ...Application.a
...Application is injected at
...Application_HiltComponents.SingletonC] ...Application_GeneratedInjector.injectMoonRoverApplication
In application, I tried switch to inject directly implementation class is ARepository, it worked fine.
#HiltAndroidApp
class TestApplication : Application() {
#Inject
lateinit var a: ARepository
}
But I still want to use interface. Are there any solution for it?
I think you have to use #Provides in module as below
#Module
#InstallIn(ViewModelComponent::class)
interface RepositoryModule {
#Binds
#ViewModelScoped
#Provides
fun provideARepos(impl: ARepository): IARepository
}
Also add #HiltViewModel in your view model as below
#HiltViewModel
class TestViewModel #Inject constructor(
private val useCase1: UseCase1, private val useCase2: UseCase2
) {
...
}
I hope it will help you.
in viewmodel please specify the #HiltViewModel
#HiltViewModel
class TestViewModel #Inject constructor(
private val useCase1: UseCase1, private val useCase2: UseCase2
) {
...
}
edited:-
#Module
#InstallIn(SingletonComponent::class)
object Module {
#Provides
fun ProvideImplRepo() = ImplRepo()
}
#Module
#InstallIn(ViewModelComponent::class)
abstract class RepositoryModule {
#Binds
abstract fun bindLoginRepository(impl: ImplRepo): Repo
}
I have a feature that I am migrating to Hilt. At the present moment after adding
#AndroidEntryPoint for the fragment and #HiltViewModel for the ViewModel.
The classes are below :
Interface
interface MyInterface {
fun throwValidation(errorMessage: String, #IdRes viewResId: Int)
}
Fragment
#AndroidEntryPoint
class OrderReplacementFragment : Fragment(), MyInterface {
override fun throwValidation(errorMessage: String, viewResId: Int) {
}
}
Viewmodel
#HiltViewModel
class OrderReplacementViewModel #Inject constructor(application: Application, private val validation: MyInterface,
#Named("io") private val ioContext: CoroutineContext) : AndroidViewModel(application) {
}
#Module
#InstallIn(SingletonComponent::class)
abstract class OrderReplaceCardModule {
#Module
abstract class OrderReplaceCardFragmentModule {
#Binds
abstract fun bindHandDeliveryDetailsValidationListener(impl: OrderReplacementFragment): MyInterface
}
}
However, when trying to do the build. I get the following error below :
/phone/PhoneApp_HiltComponents.java:1064: error: [Dagger/MissingBinding] com.cat.mobile.android.card.interfaces.MyInterface cannot be provided without an #Provides-annotated method.
public abstract static class SingletonC implements HybridEntryPoint,
^
com.cat.mobile.android.card.interfaces.MyInterface is injected at
com.cat.mobile.android.card.orderreplacementcard.viewmodel.OrderReplacementViewModel(…, validation, …)
com.cat.mobile.android.card.orderreplacementcard.viewmodel.OrderReplacementViewModel is injected at
com.cat.mobile.android.card.orderreplacementcard.viewmodel.OrderReplacementViewModel_HiltModules.BindsModule.binds(vm)
#dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.cat.mobile.phone]
How best can I go in resolving this issue ?
I want to pass Callbacks which is an interface to this RepositoryImpl class like this:
class RepositoryImpl #Inject constructor(
private val callbacks: Callbacks
) : Repository { }
This is the interface:
interface Callbacks {
fun onSomethingHappened()
}
And I want to use this Callbacks interface in a fragment like this:
#AndroidEntryPoint
class MainFragment : Fragment(), Callbacks {
override fun onSomethingHappened() {}
}
How should I write the Hilt Module to be able to provide the Callbacks interface to the RepositoryImpl class?
This is what my current project looks like without the Callbacks interface:
AppMain.kt:
#HiltAndroidApp
class AppMain : Application()
MainActivity.kt
#AndroidEntryPoint
class MainActivity : AppCompatActivity(){}
MainFragment.kt
#AndroidEntryPoint
class MainFragment : Fragment() {
#Inject
lateinit var repository: Repository
}
RepositoryImpl.kt
class RepositoryImpl #Inject constructor() : Repository { }
Repository.kt
interface Repository { }
HiltModule.kt
#Module
#InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
#Binds
abstract fun bindRepository(repositoryImpl: RepositoryImpl): Repository
}
I'm wondering, why my injecting works only in activity:
it works:
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
#Inject lateinit var fakeRepo: FakeRepo
}
#Module
#InstallIn(ActivityComponent::class)
abstract class MainModule {
#Binds
abstract fun bindFakeRepo(fakeRepoImpl: FakeRepoImpl): FakeRepo
}
BUT when I'm trying inject this repo to viewModel this way it gives errors:
#Module
#InstallIn(MainActivityViewModel::class)
abstract class MainModule {
#Binds
abstract fun bindFakeRepo(fakeRepoImpl: FakeRepoImpl): FakeRepo
}
interface FakeRepo {
fun getData(): List<Int>
}
class FakeRepoImpl #Inject constructor(): FakeRepo {
override fun getData(): List<Int> {
return listOf(3,5,6)
}
}
#HiltViewModel
class MainActivityViewModel #Inject constructor(val fakeRepo: FakeRepo) : ViewModel() {
}
Why it doesn't work ? I get
#InstallIn, can only be used with #DefineComponent-annotated classes
Probably I can inject it using provide as singleton but this is not the solution.
Could someone explain why I can inject to activity but to viewmodel not using #Binds ?
I have an app that implements MVP pattern and I want to simplify boilerplate code with Hilt. So far so good. The problem comes when I want to Inject a presenter that takes as a paramter a interface implementation of MyView, but I want to pass a implementation of an interface that inherits MyView because the presenter may be injected in diferent fragments with diferent MyView implementations
My presenter:
class BluetoothPresenter #Inject constructor(
#ApplicationContext private val context: Context,
private val view: MyView
) {
The presenter is injected in the Fragment:
class DevicesListFragment() : Fragment(), DevicesListMyView {
#Inject
lateinit var btPresenter: BluetoothPresenter
DevicesListView is a interface that inherits MyView interface
interface DevicesListView : MyView {
fun onSearchDevicesStarted();
fun searchDevicesFinished();
fun onDeviceFound(device: BluetoothDevice)
}
MyView:
interface MyView {
fun showError()
fun showMessage()
}
My module that tells Hilt how to provide the MyView:
#Module
#InstallIn(SingletonComponent::class)
interface MainModule {
#Binds
fun provideView(devicesListFragment: DevicesListView) : MyView
#Binds
fun provideDeviceView(devicesListFragment: DevicesListFragment) : DevicesListView
}
I get this error:
kotlin.UninitializedPropertyAccessException: lateinit property btPresenter has not been initialized
Thanks