匕首2不注入sharedPreference

jon*_*ney 2 android dependency-injection kotlin dagger-2

嗨,我是匕首2的新手,并尝试在下面的MyActivity类中注入sharedPreference的实例:

class MyApplication : Application() {

    companion object {
        @JvmStatic lateinit var applicationComponent : ApplicationComponent
    }



    override fun onCreate() {
        super.onCreate()
        applicationComponent = DaggerApplicationComponent.builder().androidModule(AndroidModule(this)).build()

    }
}
Run Code Online (Sandbox Code Playgroud)

这是组件和模块

@Singleton
@Component(modules = arrayOf(AndroidModule::class))
interface ApplicationComponent {
    fun inject(mainActivity: MainActivity)
}

@Module
class AndroidModule (private val application: Application){ 

    @Provides
    @Singleton
    fun provideApplicationContext() : Context = application

    @Provides
    @Singleton
    fun provideSharedPreference() : SharedPreferences = application.getSharedPreferences("shared pref", Context.MODE_PRIVATE)

}


class MainActivity: Activity{
    @Inject
    internal lateinit var sharedPreference: SharedPreferences

    @Inject
    internal lateinit var MainScreenPresenter: MainScreenContract.Presenter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_Screen)
        MyApplication.applicationComponent.inject(this)

        sharedPreference.toString()

        initiateViews()
    }

}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Error:(7, 1) error: android.content.SharedPreferences cannot be provided without an @Provides- or @Produces-annotated method.
Run Code Online (Sandbox Code Playgroud)

ale*_*bel 7

您做的有点不正确。首先,现在有了Dagger-android,它可以解决一些原理性问题,该问题解决了组件(例如Activity)不应该知道注入如何发生的问题。

您可以在这里阅读:https : //medium.com/@iammert/new-android-injector-with-dagger-2-part-1-8baa60152abe

只是为了确保匕首依赖项在Android项目中:

android {
     kapt {
        generateStubs = true
    }
}

compile "com.google.dagger:dagger:2.13"
compile "com.google.dagger:dagger-android:2.13"
compile "com.google.dagger:dagger-android-support:2.13"
kapt "com.google.dagger:dagger-compiler:2.13"
kapt "com.google.dagger:dagger-android-processor:2.13"
Run Code Online (Sandbox Code Playgroud)

您的错误是您没有告诉图形要注入MainActivity。以最佳方式应该Subcomponent为MainActivity 创建,将其与另一个MainActivity模块连接,该模块具有要注入到MainActivity中的注入,在AppComponent中设置与Subcomponent的连接,并且仅在MainAcitivy onCreate()方法中注入依赖关系图。但是使用Dagger-android,一切都变得更加容易。

这是代码:

@Singleton
@Component(modules = [
    AndroidSupportInjectionModule::class,
    ActivityBindingModule::class,
    AppModule::class
])
interface AppComponent : AndroidInjector<DaggerApplication> {

    fun inject(application: MyApplication)

    override fun inject(instance: DaggerApplication)

    @Component.Builder
    interface Builder {
        @BindsInstance fun application(application: MyApplication): Builder
        fun build(): AppComponent
    }
}
Run Code Online (Sandbox Code Playgroud)

AndroidSupportInjectionModule.class:这来自dagger.android.support库。并且它通过我们的模块提供了Android组件(活动/片段/服务/ BroadcastReceiver / ContentProvider)。

dagger2.10中的@ Component.Builder为我们提供了更好的创建DaggerAppComponent构建器的方法。

Builder中的@BindsInstance将自动创建的实例,MyApplication因此AppModule我们无需使用MyApplication实例化。它已经是图中的依赖项。

ActivityBindingModule.clas是我们的。我稍后再讲。

您可以在此处阅读有关此部分的更多信息:https : //proandroiddev.com/dagger-2-component-builder-1f2b91237856

接下来是AppModule.class:

@Module
abstract class AppModule{

    @Binds
    abstract fun provideContext(application: MyApplication) : Context

    @Module
    companion object {

        @JvmStatic
        @Provides
        fun provideSharedPreferences(context: Context): SharedPreferences =
            context.getSharedPreferences("SharedPreferences", Context.MODE_PRIVATE)
    }
}
Run Code Online (Sandbox Code Playgroud)

@Binds注释替换@Provides注释,它只返回函数参数中的值。如您所见,图中已经存在MyApplication的实例,因此无需在AppModule构造函数中注入MyApplication。

注意:带@Binds批注的函数应该是抽象的,如果有带@Provides批注的函数应该是static。您可以在Kotlin中找到有关静态函数的解决方案:https : //github.com/google/dagger/issues/900

ActivityBindingModule.class:

@Module
abstract class ActivityBindingModule {

    @ContributesAndroidInjector(modules = [MainActivityModule::class])
    internal abstract fun bindMainActivity(): MainActivity
}
Run Code Online (Sandbox Code Playgroud)

使用ActivityBindingModule类,我们只创建了一个单独的Module,它将为我们为Android组件创建组件。

有关ContributesAndroidInjector和Binds的更多信息,您可以在此处阅读:https : //proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f

MainActivityModule.class:

@Module
abstract class MainActivityModule {

    @Binds
    internal abstract fun provideMainActivity(activity: MainActivity): MainActivity
}
Run Code Online (Sandbox Code Playgroud)

MyApplication.class:

class MyApplication: DaggerApplication(){

    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        val appComponent = DaggerAppComponent.builder()
            .application(this)
            .build()
        appComponent.inject(this)
        return appComponent
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记在Mainfest文件中插入Application。

<application
    android:name=".MyApplication"
...
>
    ...
</application>
Run Code Online (Sandbox Code Playgroud)

对于您的Application类,您需要实现实现HasActivityInjector / HasFragmentInjector / etc的DaggerApplication,并调用AndroidInjection.inject()。

关于这一点,您可以在这里了解更多信息:https : //google.github.io/dagger/android.html

MainActivity.class:

class MainActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var sharedPreferences: SharedPreferences

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.d("TAAAAG", sharedPreferences.toString())
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,MainActivity现在不知道如何注入SharedPreferences。实际上AndroidInjection.inject(this);在DaggerAppCompatActivity中。如果您不从中扩展您的类,那么您需要自己在onCreate方法中指定它,否则将不会进行注入。

编辑: 您可以从GitHub检查代码:https : //github.com/Belka1000867/Dagger2Kotlin