Why it still works without installing AndroidInjec

2019-04-10 07:25发布

问题:

According to Dagger documentation about injecting activity objects, it says that installing AndroidInjectionModule in your application component. However, everything is fine without it.

Does it means that I don't need to declare it? Under what circumstances will it be wrong?

For example:
Injected instance

data class Food(val name: String)

Module

@Module
class FoodModule{
    @Provides
    fun provideFood(): Food {
        return Food("cholocate")
    }
}

BindingModule

@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = [FoodModule::class])
    abstract fun FoodShop(): MainActivity
}

AppComponent (Without installing AndroidInjectionModule)

@Component(modules = [MainActivityModule::class])
interface AppComponent{
    fun inject(app: App)
}

App

class App : Application(), HasActivityInjector {
    @Inject
    lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent.create().inject(this)
    }

    override fun activityInjector(): AndroidInjector<Activity> {
        return dispatchingActivityInjector
    }
}

MainActivity

class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var food: Food

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.d("test", "Get ${food.name}")
    }
}

It get chocolate successfully in MainActivity.

回答1:

Does it means that I don't need to declare it? Under what circumstances will it be wrong?

It actually seems like you don't need to declare it, but it might lead to compile errors if you don't.


If you have a look at AndroidInjectionModule you can see that it just lists a bunch of @Multibinds methods for framework types.

@Multibinds
abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
    activityInjectorFactories();

Now if you look up Declaring @Multibinds you can read that

You do not have to use @Multibinds for sets or maps that have at least one @IntoSet, @ElementsIntoSet, or @IntoMap binding, but you do have to declare them if they may be empty.

And to declare them if they may be empty is exactly what the AndroidInjectionModule module is doing for you. If the Android Injection parts would require an undefined Map of injector factories you would probably get a compile time error stating that it cannot be provided.

The reason that you don't need the module is because you're using @ContributesAndroidInjector, of which the generated code will contain a @Binds @IntoMap etc. method, that declares the bindings map. Stated above—as it is not empty anymore—you would not need the additional @Multibinds declaration that AndroidInjectionModule provides for the non-empty multibinding.


You might not need the module, but it will declare all the framework injector factories for you in case that they might be empty, possibly preventing one or two compile errors. After all the javadoc simply states that it should be installed, not that it must.

This module should be installed in the component that is used to inject the Application class.



标签: dagger-2