Dagger2 + Kotlin:lateinit属性尚未初始化

Gui*_*ira 12 android kotlin dagger-2

我正在尝试将ViewModelFactory注入到我的Activity中,但它仍然抛出同样的错误:lateinit属性viewModelFactory尚未初始化.我找不到我可能做错的事.从我的课程中查看上面的代码

AppComponent.kt

@Component(modules = [(AppModule::class), (NetworkModule::class), (MainModule::class)])
interface AppComponent {

    fun inject(application: TweetSentimentsApplication)

    fun inject(mainActivity: MainActivity)

    fun context(): Context

    fun retrofit(): Retrofit
}
Run Code Online (Sandbox Code Playgroud)

MainModule.kt

@Module
class MainModule {

    @Provides
    fun mainViewModelFactorty(repository: TweetRepository): MainViewModelFactory = MainViewModelFactory(repository)

    @Provides
    fun local(database: AppDatabase): TweetLocal = TweetLocal(database)

    @Provides
    fun remote(tweetService: TweetService): TweetRemote = TweetRemote(tweetService)

    @Provides
    fun tweetService(retrofit: Retrofit): TweetService = retrofit.create(TweetService::class.java)

    @Provides
    fun repository(local: TweetLocal, remote: TweetRemote): TweetRepository = TweetRepository(local, remote)

}
Run Code Online (Sandbox Code Playgroud)

MainActivity.kt

class MainActivity : AppCompatActivity() {

    @Inject lateinit var viewModelFactory: MainViewModelFactory

    private val viewModel: MainViewModel? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)

        viewModel?.init("guuilp")
        viewModel?.getTweetList()?.observe(this, Observer {
            Toast.makeText(this, it?.size.toString(), Toast.LENGTH_LONG).show()
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

TweetSentimentsApplication.kt

open class TweetSentimentsApplication: Application(){

    companion object {
        lateinit var appComponent: AppComponent
    }

    override fun onCreate() {
        super.onCreate()

        initDI()
    }

    private fun initDI() {
        appComponent = DaggerAppComponent.builder()
                .appModule(AppModule(this))
                .build()
    }
}
Run Code Online (Sandbox Code Playgroud)

zsm*_*b13 14

您必须在初始化时调用inject(mainActivity: MainActivity)您已定义的方法,这就是Dagger实际注入您需要的依赖项的方式.AppComponentMainActivity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)

    // This is where the dependencies are injected
    TweetSentimentsApplication.appComponent.inject(this)

    ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)

    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,根据文档,这不是真的。Dagger 假设在不需要你执行“注入”的情况下注入依赖项 - “如果你的类有 Inject-annotated 字段但没有 Inject-annotated 构造函数,Dagger 将在需要时注入这些字段,但不会创建新实例。添加一个 no -argument 构造函数带有 @Inject 注释,以指示 Dagger 也可以创建实例。” - Kotlin 似乎违反了这一声明。 (2认同)

小智 9

此外,请确保您的应用程序名称已添加到AndroidManifest.xml文件中。

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

  • 在 dagger2 上花费了一整天时间来查找问题之后,我看到了此评论并将应用程序类添加到清单中。这是一个愚蠢的错误,但有想过 (2认同)

Dro*_*use 5

您还可以这样做:

  @Inject
  lateinit var viewModelFactory: ViewModelProvider.Factory
  val mainViewModel: MainViewModel by lazy {
      ViewModelProviders.of(this, viewModelFactory)[MainViewModel::class.java]
  }
Run Code Online (Sandbox Code Playgroud)

并将抽象模块与@ContributesAndroidInjector一起用于活动,并使用抽象模块作为视图模型。使用抽象更有效:

   @Module
   abstract class AndroidBindingModule {

   @ContributesAndroidInjector
    internal abstract fun contributesAnActivity(): AnActivity
    }



 @Module
    abstract class ViewModelModule {
      //the default factory only works with default constructor
      @Binds
      @IntoMap
      @ViewModelKey(AViewModel::class)
      abstract fun bindArtViewModel(aViewModel: AViewModel): ViewModel

      @Binds
      abstract fun bindViewModelFactory(factory: AViewModelFactory): ViewModelProvider.Factory
    }





 @Documented
    @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
    @Retention(RetentionPolicy.RUNTIME)
    @MapKey
    internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
Run Code Online (Sandbox Code Playgroud)