Dagger - Dependency inject into Activity - kotlin

I have a main activity as below:
#AndroidEntryPoint
class MainActivity : BaseActivity() {
#Inject
lateinit var configuration: Configuration
...
}
And a module defined like:
#Module
#InstallIn(SingletonComponent::class)
class AppModules {
#Singleton
#Provides
fun bindDeviceConfig(): Configuration {
return Configuration()
}
}
When I try running this it gives an error:
lateinit property configuration has not been initialized
I've looked at the documentation and can't seem to get my head around why I'm getting this issue. Does anyone know why?

Related

Dagger hilt get scope object in injected object

How get scope object (like ViewModel, Fragment etc where I inject) in injected object?
I finded only #ActivityContext annotation that give you activity but i need ViewModel
#HiltViewModel
class SomeViewModel #Inject constructor(
savedStateHandle: SavedStateHandle
) : ViewModel() {
#Inject lateinit var someObj: SomeInjectedObject
//some code
}
class SomeInjectedObject #Inject constructor(){
// how can i get here view model link ?
}
I can just set it in init block but it looks like incorrect decision
#HiltViewModel
class SomeViewModel #Inject constructor(
savedStateHandle: SavedStateHandle,
var someObj: SomeInjectedObject
) : ViewModel() {
init{
someObj.vm = this
}
//some code
}
class SomeInjectedObject #Inject constructor(){
var vm: ViewModel
}

Hilt using In recyclerView Adapter for Picassso framework

I try to Hilt injection in RecyclerView Adapter but it throw me this error;
public final class RecyclerAdapterPhotos extends androidx.recyclerview.widget.RecyclerView.Adapter<com.packagename.projectName.RecyclerAdapters.RecyclerAdapterPhotos.PhotosVH> {
#AndroidEntryPoint base class must extend ComponentActivity, (support) Fragment, View, Service, or BroadcastReceiver.
Head My adapter.
#AndroidEntryPoint
class RecyclerAdapterPhotos(var context:Context, private val photoList:List\<PhotosModelItem\>):RecyclerView.Adapter\<RecyclerAdapterPhotos.PhotosVH\>() {
#Inject
lateinit var imageLoader:ImageLoaderHiltClass
...
override fun onBindViewHolder(holder: PhotosVH, position: Int) {
imageLoader.imageLoader(photoList[position].thumbnailUrl,holder.photosThumbnailVH)
...
Module of Picasso
#Module
#InstallIn(SingletonComponent::class)
object ImageLoaderModule {
#Provides
fun ProvidesImageLoader(photoUri:String,photoVH:ImageView):Picasso{
return Picasso.get()
}
I try to use Hilt for Picasso frame in my recyclerView adapter

Dagger #Provides in Kotlin

I'm trying to understand Dagger. I created applicationInjector class :
class BaseApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication>? {
return DaggerAppComponent.builder().application(this)?.build()
}
}
And here's my AppComponent
#Component(
modules = [AndroidSupportInjectionModule::class,
ActivityBuilderModules::class]
)
interface AppComponent : AndroidInjector<BaseApplication> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application?): Builder?
fun build(): AppComponent?
}
}
Now what I want to do is to to inject simple String to Activity (really basic, right ?)
In Java it works like this :
#Module
abstract class ActivityBuilderModules {
#ContributesAndroidInjector
abstract fun contributeAuthActivity() : AuthActivity
//JAVA
#Provides
public static String provideTestString() {
return "TEST "
}
however we don't have static function in Kotlin, right ? And it needs to be static cause I'm getting an error :
error: com.example.kotlintests.di.ActivityBuilderModules is abstract and has instance #Provides methods. Consider making the methods static or including a non-abstract subclass of the module instead.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.kotlintests.BaseApplication> {
I tried with package level function but it didn't work. How can I add provideTestString function in Kotlin ?

How to provide the base class in Koin?

For example I the following classes:
abstract class BaseClass()
class SpecificClass : BaseClass()
Now, I want to provide SpecificClass through koin dependency inject but I also want to provide the base class BaseClass in the same graph.
To be clear I want to do something like:
class Someclass {
...
private specificClass: SpecificClass by inject()
...
}
class Someclass {
...
private baseClass: BaseClass by inject()
// where this BaseClass is just the the same instace of the SpecificClass in the dependency graph
...
}
How do I do my module to do this? How can I inject the implementation instance to the baseClass reference?
You can do it using Koin in 2 ways
Methodn 1
You can create dependencies for both of them like this
single {
SpecificClass()
}
single<BaseClass> {
get<SpecificClass>()
}
In this way, whenever you inject an instance, it will get injected accordingly
Method 2
You can make use of named dependencies like this
single("BaseClassImpl") {
SpecificClass()
}
And when you want to inject it, provide key for that dependency like this:
class Someclass {
...
private specificClass: SpecificClass by inject("BaseClassImpl")
...
}
class Someclass {
...
private baseClass: BaseClass by inject("BaseClassImpl")
// where this BaseClass is just the the same instace of the SpecificClass in the dependency graph
...
}
You can't inject abstract classes.
In order to inject a class, it must be instantiable and abstract classes are not.
To inject SpecificClass with Koin you need to create a module:
val appModule = module {
single {
SpecificClass()
}
}
Initialize it in your application class:
class MyApplication : Application() {
override fun onCreate(){
super.onCreate()
// start Koin!
startKoin {
// declare used Android context
androidContext(this#MyApplication)
// declare modules
modules(appModule)
}
}
}
And use the inject delegation in your activity/fragment
class MyActivity() : AppCompatActivity() {
val specificClass : SpecificClass by inject()
}

Dagger: Inject named string in constructor

I have a properties file and I would like to inject a property in a service.
I would like use the constructor method for DI like this:
#Inject
public ScanService(#Named("stocks.codes") String codes, IYahooService yahooService) {
this.yahooService = yahooService;
this.codes = codes;
}
I try to do a module like specified in this link => Dagger: Inject #Named strings?
#Provides
#Named("stocks.code")
public String providesStocksCode() {
return "test";
}
And for the provider method for my service:
#Provides
#Singleton
public IScanService provideScanService(String codes, IYahooService yahooService){
return new ScanService(codes, yahooService);
}
When I run the compilation I get this error:
[ERROR]
/Users/stocks/src/main/java/net/modules/TestModule.java:[22,7]
error: No injectable members on java.lang.String. Do you want to add
an injectable constructor? required by
provideScanService(java.lang.String,net.IYahooService)
for net.modules.TestModule
How can I inject my property correctly in the constructor ?
Thanks.
You have two different names: stocks.codes and stocks.code.
You will also have to annotate your provideScanService codes parameter:
#Provides
#Singleton
public IScanService provideScanService(#Named("stocks.codes") String codes, IYahooService yahooService){
return new ScanService(codes, yahooService);
}
Or do it like this:
#Provides
#Singleton
public IScanService provideScanService(ScanService scanService){
return scanService;
}
If you mean Dagger 2, I can help you.
First you have to declare dependencies in Component
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
#Named("cloud") UserDataSource userCloudSource();
#Named("disc") UserDataSource userDiscSource();
UserDataRepository userDataRepository();
}
then instantiate it in Module
#Module
public class ApplicationModule {
#Provides #Named("cloud")
UserDataSource provideCloudUserSource(UserCloudSource userSource) {
return userSource;
}
#Provides #Named("disc")
UserDataSource provideDiscUserSource(UserDiscSource userSource) {
return userSource;
}
#Provides
UserDataRepository provideUserRepository(UserDataRepository repository) {
return repository;
}
}
then inject it in constructor with #Named qualifiers
#Inject
public UserDataRepository(#Named("cloud") UserDataSource cloudSource,
#Named("disc") UserDataSource discSource) {
this.cloudDataSource= cloudSource;
this.discDataSource = discSource;
}