Search code examples
kotlindagger-2

Field injection in kotlin is always null


I am trying to do a field injection in a non Activity class, but I am always getting that the field has not been initialized/null. I have read Can I use Dagger 2's field injection in Kotlin?, also Dagger 2 on Android @Singleton annotated class not being injected, and still have the same problem. Here is how I have setted it up

This is the model class

class Greetings {
    val sayHello: String = "Hello from Dagger 2" 
}

This is the module class

@Module
class GreetingsModule {
    @Provides
    @Singleton
    fun providesGreetings(): Greetings {
        return Greetings()
    }
}

This is the component

@Singleton
@Component(modules = arrayOf(GreetingsModule::class))
interface GreetingsComponent {
    fun inject(mainActivity: MainActivity)
    fun inject(testGreetings: TestGreetings)
}

And the class that extends from Application

class App: Application() {
    private lateinit var greetingsComponent: GreetingsComponent
    override fun onCreate() {
        super.onCreate()
        greetingsComponent = DaggerGreetingsComponent.builder().build()
    }
    fun getGreetings() = greetingsComponent
}

And this is how I am injecting it into another class and where is null/not initialized

class TestGreetings {
    @Inject
    lateinit var greetings: Greetings
    fun checkIfNull() {
        if  (greetings != null) {
            Log.d("INFO", "${ greetings.sayHello}")
        } else {
            Log.d("INFO", "null !!!!!!")

        }
    }
}

What exactly I am doing wrong??


Solution

  • ok, I'll try to answer

    You can't use Field Injection which is Greetings in TestGreetings class because Dagger doesn't know how to inject it.

    Field Injection is usually used, for components that is related to Android Framework, so in your case is MainActivity

    TestGreetings class is not Android Framework class, so it is better to use Constructor Injection, like this

    class TestGreetings(private val greetings: Greetings) {
    
        fun checkIfNull() {
            if  (greetings != null) {
                Log.d("INFO", "${ greetings.sayHello}")
            } else {
                Log.d("INFO", "null !!!!!!")
    
            }
        }
    }
    

    In order for Dagger to know how to initialize TestGreetings class, you need to define it in GreetingsModule class

    @Module
    class GreetingsModule {
        ...
        @Provides
        @Singleton
        fun providesTestGreetings(greetings: Greetings): TestGreetings {
            return TestGreetings(greetings)
        }
    }
    

    Now you can use TestGreetings class in MainActivity

    class MainActivity: AppCompatActivity() {
       @Inject
       lateinit var testGreetings: TestGreetings
       
       override fun onCreate(savedInstanceState: Bundle?) {
           ...
           testGreetings.checkIfNull()
       }
    }
    

    Lastly, you can remove fun inject(testGreetings: TestGreetings) in GreetingsComponent

    P.s. Make sure your Dagger setup in MainActivity is correct

    Hopefully this clear the things out :)