Dagger 2 injecting Android Application Context
I have read this article and it was very helpful.
https://medium.com/tompee/android-dependency-injection-using-dagger-2-530aa21961b4
Sample code.
Update: I removed from AppComponent.kt these lines because are not necessaries
fun context(): Context
fun applicationContext(): Application
AppComponent.kt
@Singleton
@Component(
modules = [
NetworkModule::class,
AppModule::class
]
)
interface AppComponent {
fun inject(viewModel: LoginUserViewModel)
}
AppModule.kt
@Module
class AppModule(private val application: Application) {
@Provides
@Singleton
fun providesApplication(): Application = application
@Provides
@Singleton
fun providesApplicationContext(): Context = application
@Singleton
@Provides
fun providesNetworkConnectivityHelper(): NetworkConnectivityHelper{
return NetworkConnectivityHelper(application.applicationContext)
}
}
NetworkConnectivityHelper.kt
And only added @Inject constructor to pass the Context
class NetworkConnectivityHelper @Inject constructor(context: Context) {
private val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
@Suppress("DEPRECATION")
fun isNetworkAvailable(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val nc = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
nc != null
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
}
App class.kt
class App : Application() {
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
this.appComponent = this.initDagger()
}
private fun initDagger() = DaggerAppComponent.builder()
.appModule(AppModule(this))
.build()
}
Finally in my Activity I injected my helper
@Inject lateinit var networkConnectivity: NetworkConnectivityHelper
And YEI! it works for me.
@Module
public class MainActivityModule {
private final Context context;
public MainActivityModule (Context context) {
this.context = context;
}
@Provides //scope is not necessary for parameters stored within the module
public Context context() {
return context;
}
}
@Component(modules={MainActivityModule.class})
@Singleton
public interface MainActivityComponent {
Context context();
void inject(MainActivity mainActivity);
}
And then
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(MainActivity.this))
.build();
It took me a while to find a proper solution, so thought it might save some time for others, as far as I could gather this is the preferred solution with the current Dagger version (2.22.1).
In the following example I need the Application
's Context
to create a RoomDatabase
(happens in StoreModule
).
Please if you see any errors or mistakes let me know so I'll learn as well :)
Component:
// We only need to scope with @Singleton because in StoreModule we use @Singleton
// you should use the scope you actually need
// read more here https://google.github.io/dagger/api/latest/dagger/Component.html
@Singleton
@Component(modules = { AndroidInjectionModule.class, AppModule.class, StoreModule.class })
public interface AwareAppComponent extends AndroidInjector<App> {
// This tells Dagger to create a factory which allows passing
// in the App (see usage in App implementation below)
@Component.Factory
interface Factory extends AndroidInjector.Factory<App> {
}
}
AppModule:
@Module
public abstract class AppModule {
// This tell Dagger to use App instance when required to inject Application
// see more details here: https://google.github.io/dagger/api/2.22.1/dagger/Binds.html
@Binds
abstract Application application(App app);
}
StoreModule:
@Module
public class StoreModule {
private static final String DB_NAME = "aware_db";
// App will be injected here by Dagger
// Dagger knows that App instance will fit here based on the @Binds in the AppModule
@Singleton
@Provides
public AppDatabase provideAppDatabase(Application awareApp) {
return Room
.databaseBuilder(awareApp.getApplicationContext(), AppDatabase.class, DB_NAME)
.build();
}
}
App:
public class App extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
// Using the generated factory we can pass the App to the create(...) method
DaggerAwareAppComponent.factory().create(this).inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}