Dagger 2 注入 Android 应用上下文
Dagger 2 injecting Android Application Context
我正在使用 Dagger 2 并让它正常工作,但是我现在需要访问 Android 应用程序上下文.
我不清楚如何注入和访问上下文。我尝试按如下方式执行此操作:
@Module
public class MainActivityModule {
private final Context context;
MainActivityModule(Context context) {
this.context = context;
}
@Provides @Singleton
Context provideContext() {
return context;
}
}
但是这会导致以下异常:
java.lang.RuntimeException: Unable to create application : java.lang.IllegalStateException: mainActivityModule must be set
如果我检查 Dagger 生成的代码,则会在此处引发此异常:
public Graph build() {
if (mainActivityModule == null) {
throw new IllegalStateException("mainActivityModule must be set");
}
return new DaggerGraph(this);
}
我不确定这是否是注入 Context 的正确方法 - 任何帮助将不胜感激。
未正确构建应用程序组件,需要传入应用程序。这个 Dagger 2 示例完美地展示了如何做到这一点:https://github.com/google/dagger/tree/master/examples/android-simple/src/main/java/com/example/dagger/simple
@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);
}
然后
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(MainActivity.this))
.build();
我花了一段时间才找到合适的解决方案,所以我认为这可能会为其他人节省一些时间,据我所知,这是当前 Dagger 版本 (2.22.1) 的首选解决方案。
在下面的示例中,我需要 Application
的 Context
来创建 RoomDatabase
(发生在 StoreModule
中)。
如果您发现任何错误或错误,请告诉我,我也会学习 :)
组件:
// 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> {
}
}
应用模块:
@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);
}
商店模块:
@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();
}
}
应用程序:
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;
}
}
我已经阅读了这篇文章,它很有帮助。
https://medium.com/tompee/android-dependency-injection-using-dagger-2-530aa21961b4
示例代码。
更新: 我从 AppComponent.kt 中删除了这些行,因为它们不是必需的
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
并且只添加了@Inject构造函数来传递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
}
}
应用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()
}
终于在我的 Activity 中注射了我的帮手
@Inject lateinit var networkConnectivity: NetworkConnectivityHelper
还有耶!它对我有用。
可能我们可以注入上下文,如下所示:
应用程序组件
@Component(
modules = [
(ApplicationModule::class),
(AndroidSupportInjectionModule::class),
(UiBindingModule::class)
]
)
interface ApplicationComponent : AndroidInjector<AndroidApplication> {
override fun inject(application: AndroidApplication)
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: AndroidApplication): Builder
@BindsInstance
fun context(context: Context): Builder
fun build(): ApplicationComponent
}
}
自定义应用扩展匕首应用
class AndroidApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerApplicationComponent.builder().application(this).context(this).build()
}
}
示例应用程序模块
@Module
abstract class ApplicationModule {
/**
* Binds a background thread executor, which executes threads from a thread pool
* @param jobExecutor
* @return
*/
@Binds
internal abstract fun provideThreadExecutor(jobExecutor: JobExecutor): ThreadExecutor
/**
* Binds main ui looper thread
* @param uiThread
* @return
*/
@Binds
internal abstract fun providePostExecutionThread(uiThread: UIThread): PostExecutionThread
}
示例UI绑定模块
@Module
abstract class UiBindingModule {
@ContributesAndroidInjector(modules = [(MainActivityModule::class)])
internal abstract fun mainActivity(): MainActivity
@ContributesAndroidInjector(modules = [(MapFragmentModule::class)])
internal abstract fun mapFragment(): MapFragment
}
@Singleton
@Component(modules = [YourModule::class, ThatOtherModule::class])
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance fun applicationContext(applicationContext: Context): Builder
fun build(): ApplicationComponent
}
}
class YourApplication : Application() {
val component: ApplicationComponent by lazy {
DaggerApplicationComponent.builder()
.applicationContext(applicationContext)
.build()
}
}
- 使用
@BindInstance
声明一个提供上下文依赖的抽象函数。即 @BindsInstance fun applicationContext(applicationContext: Context): Builder
- 使用
.applicationContext(applicationContext)
设置上下文
我正在使用 Dagger 2 并让它正常工作,但是我现在需要访问 Android 应用程序上下文.
我不清楚如何注入和访问上下文。我尝试按如下方式执行此操作:
@Module
public class MainActivityModule {
private final Context context;
MainActivityModule(Context context) {
this.context = context;
}
@Provides @Singleton
Context provideContext() {
return context;
}
}
但是这会导致以下异常:
java.lang.RuntimeException: Unable to create application : java.lang.IllegalStateException: mainActivityModule must be set
如果我检查 Dagger 生成的代码,则会在此处引发此异常:
public Graph build() {
if (mainActivityModule == null) {
throw new IllegalStateException("mainActivityModule must be set");
}
return new DaggerGraph(this);
}
我不确定这是否是注入 Context 的正确方法 - 任何帮助将不胜感激。
未正确构建应用程序组件,需要传入应用程序。这个 Dagger 2 示例完美地展示了如何做到这一点:https://github.com/google/dagger/tree/master/examples/android-simple/src/main/java/com/example/dagger/simple
@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);
}
然后
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(MainActivity.this))
.build();
我花了一段时间才找到合适的解决方案,所以我认为这可能会为其他人节省一些时间,据我所知,这是当前 Dagger 版本 (2.22.1) 的首选解决方案。
在下面的示例中,我需要 Application
的 Context
来创建 RoomDatabase
(发生在 StoreModule
中)。
如果您发现任何错误或错误,请告诉我,我也会学习 :)
组件:
// 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> {
}
}
应用模块:
@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);
}
商店模块:
@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();
}
}
应用程序:
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;
}
}
我已经阅读了这篇文章,它很有帮助。
https://medium.com/tompee/android-dependency-injection-using-dagger-2-530aa21961b4
示例代码。
更新: 我从 AppComponent.kt 中删除了这些行,因为它们不是必需的
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
并且只添加了@Inject构造函数来传递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
}
}
应用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()
}
终于在我的 Activity 中注射了我的帮手
@Inject lateinit var networkConnectivity: NetworkConnectivityHelper
还有耶!它对我有用。
可能我们可以注入上下文,如下所示:
应用程序组件
@Component(
modules = [
(ApplicationModule::class),
(AndroidSupportInjectionModule::class),
(UiBindingModule::class)
]
)
interface ApplicationComponent : AndroidInjector<AndroidApplication> {
override fun inject(application: AndroidApplication)
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: AndroidApplication): Builder
@BindsInstance
fun context(context: Context): Builder
fun build(): ApplicationComponent
}
}
自定义应用扩展匕首应用
class AndroidApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerApplicationComponent.builder().application(this).context(this).build()
}
}
示例应用程序模块
@Module
abstract class ApplicationModule {
/**
* Binds a background thread executor, which executes threads from a thread pool
* @param jobExecutor
* @return
*/
@Binds
internal abstract fun provideThreadExecutor(jobExecutor: JobExecutor): ThreadExecutor
/**
* Binds main ui looper thread
* @param uiThread
* @return
*/
@Binds
internal abstract fun providePostExecutionThread(uiThread: UIThread): PostExecutionThread
}
示例UI绑定模块
@Module
abstract class UiBindingModule {
@ContributesAndroidInjector(modules = [(MainActivityModule::class)])
internal abstract fun mainActivity(): MainActivity
@ContributesAndroidInjector(modules = [(MapFragmentModule::class)])
internal abstract fun mapFragment(): MapFragment
}
@Singleton
@Component(modules = [YourModule::class, ThatOtherModule::class])
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance fun applicationContext(applicationContext: Context): Builder
fun build(): ApplicationComponent
}
}
class YourApplication : Application() {
val component: ApplicationComponent by lazy {
DaggerApplicationComponent.builder()
.applicationContext(applicationContext)
.build()
}
}
- 使用
@BindInstance
声明一个提供上下文依赖的抽象函数。即@BindsInstance fun applicationContext(applicationContext: Context): Builder
- 使用
.applicationContext(applicationContext)
设置上下文