Dagger2 + Kotlin:lateinit 属性尚未初始化
Posted
技术标签:
【中文标题】Dagger2 + Kotlin:lateinit 属性尚未初始化【英文标题】:Dagger2 + Kotlin: lateinit property has not been initialized 【发布时间】: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()
【问题讨论】:
【参考方案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 不像它宣传的那样运行时安全。虽然它不能为@Inject
ed 字段分配实例,但它仍然允许项目编译【参考方案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()
)
【讨论】:
这仅在您设置@ContributesAndroidInjector
和HasActivityinjector
s 时有效。【参考方案5】:
我的错误是创建一个新对象并从中获取一个组件,例如App().component
。
所以在这种情况下,您需要将组件字段放入companion object
,并将代码替换为App.component
【讨论】:
【参考方案6】:也许您错过了在片段/活动中实现“可注入”接口。这将片段/活动标记为可注入。
【讨论】:
以上是关于Dagger2 + Kotlin:lateinit 属性尚未初始化的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin Autowired 问题 - lateinit (obv)
kotlin.UninitializedPropertyAccessException:lateinit 属性尚未初始化