【问题标题】:Dagger 2 injecting Android Application ContextDagger 2 注入 Android 应用程序上下文
【发布时间】:2015-08-21 22:29:23
【问题描述】:

我正在使用 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:无法创建应用程序:java.lang.IllegalStateException:必须设置 mainActivityModule

如果我检查 Dagger 生成的代码,这里会引发此异常:

public Graph build() {  
    if (mainActivityModule == null) {
        throw new IllegalStateException("mainActivityModule must be set");
    }
    return new DaggerGraph(this);
}

我不确定这是否是注入上下文的正确方法 - 任何帮助将不胜感激。

【问题讨论】:

  • 我不确定注入应用程序上下文是否有意义。您可以扩展应用程序类并创建应用程序的静态实例。你可以命名它,例如BaseApplication。之后,您可以在扩展的 Application 类中创建 get() 方法,该方法将返回该实例并同时成为 Application Context。然后,您可以使用以下构造从项目中的任何位置访问应用程序上下文:BaseApplication.get()。您应该谨慎使用它,并且仅在必要时使用。

标签: android dependency-injection android-context dagger-2


【解决方案1】:

未正确构建应用程序组件,需要传入应用程序。这个 Dagger 2 示例完美地展示了如何做到这一点:https://github.com/google/dagger/tree/master/examples/android-simple/src/main/java/com/example/dagger/simple

更新:
工作链接:https://github.com/yongjhih/dagger2-sample/tree/master/examples/android-simple/src/main/java/com/example/dagger/simple

【讨论】:

    【解决方案2】:
    @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();
    

    【讨论】:

    • 你能解释一下你在哪里替换 MainActivityModule 吗?
    • @IgorGanapolsky 我不知道为什么我会使用 AppContext。不过,它的工作方式基本相同。
    • @EpicPandaForce 在活动中,我应该使用 DI 还是只使用“this”?例如在 Activity 中显示 Dialog
    • 因为它不需要作用域提供程序来提供相同的实例。它只会存在一次,因为它总是从模块中的字段提供
    • 现场注入MainActivity@JohanLund的能力
    【解决方案3】:

    我花了一段时间才找到合适的解决方案,因此认为这可能会为其他人节省一些时间,据我所知,这是当前 Dagger 版本 (2.22.1) 的首选解决方案。

    在以下示例中,我需要ApplicationContext 来创建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;
        }
    }
    

    【讨论】:

    • 2020年最有用
    【解决方案4】:

    我读过这篇文章,很有帮助。

    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
        }
    }
    

    应用类.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()
    }
    

    最后在我的活动中我注入了我的助手

     @Inject lateinit var networkConnectivity: NetworkConnectivityHelper
    

    还有耶!它对我有用。

    【讨论】:

    【解决方案5】:

    也许我们可以注入如下所示的上下文:

    应用程序组件

    @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 BindingModule 示例

    @Module
    abstract class UiBindingModule {
    
        @ContributesAndroidInjector(modules = [(MainActivityModule::class)])
        internal abstract fun mainActivity(): MainActivity
    
        @ContributesAndroidInjector(modules = [(MapFragmentModule::class)])
        internal abstract fun mapFragment(): MapFragment
    
    }
    

    【讨论】:

    • 如果使用Android注入,这其实是最好的解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多