【问题标题】:Dagger2 + Kotlin: lateinit property has not been initializedDagger2 + Kotlin:lateinit 属性尚未初始化
【发布时间】:2018-11-06 08:32:23
【问题描述】:

我正在尝试将 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
}

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)

}

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

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

【问题讨论】:

    标签: android kotlin dagger-2


    【解决方案1】:

    当你初始化你的MainActivity时,你必须调用你在AppComponent中定义的inject(mainActivity: MainActivity)方法,这就是Dagger实际注入你需要的依赖的方式。

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

    【讨论】:

    • 谢谢!我正在学习 Dagger,有些东西还不是很清楚。您的回答和解释帮助很大!
    • 查看我的教程系列,从这里开始:dev.to/autonomousapps/…
    • 实际上根据文档,这是不正确的。 Dagger 假设在不需要您执行“注入”的情况下注入依赖项 - “如果您的类具有 Inject-annotated 字段但没有 Inject-annotated 构造函数,则 Dagger 将在请求时注入这些字段,但不会创建新实例。添加 no - 带有 @Inject 注释的参数构造函数,以指示 Dagger 也可以创建实例。” - Kotlin 似乎违反了此声明。
    • @AndroidDev Dagger 将注入这些字段 IF REQUESTED,也就是当您调用 component.inject(this) 时。 Kotlin 与此无关。
    • @EpicPandaForce 您所说的仅适用于这种情况下的 Android 组件。这可能意味着 Dagger 不像它宣传的那样运行时安全。虽然它不能为@Injected 字段分配实例,但它仍然允许项目编译
    【解决方案2】:

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

    <application
        android:name=".YourAppName"
        ..../>
    

    【讨论】:

    • 在 dagger2 上花费了一整天的时间来寻找问题之后,我看到了这条评论,并在清单中添加了应用程序类。这是一个愚蠢的错误,但曾经想过
    • WTF!你怎么猜的???你救了我的大脑!谢谢!
    【解决方案3】:

    您也可以这样做:

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

    并使用带有@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>)
    

    【讨论】:

      【解决方案4】:

      您还可以扩展 DaggerAppCompatActivity 来代替 AppCompatActivity。例如

      class MainActivity : DaggerAppCompatActivity() {
      
          @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()
              })
          }
      }
      

      【讨论】:

      • 这仅在您设置@ContributesAndroidInjectorHasActivityinjectors 时有效。
      【解决方案5】:

      我的错误是创建一个新对象并从中获取一个组件,例如App().component

      所以在这种情况下,您需要将组件字段放入companion object,并将代码替换为App.component

      【讨论】:

        【解决方案6】:

        也许您错过了在片段/活动中实现“可注入”接口。这将片段/活动标记为可注入。

        【讨论】:

          猜你喜欢
          • 2019-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-23
          • 2023-03-25
          • 1970-01-01
          • 2019-12-02
          • 2021-06-21
          相关资源
          最近更新 更多