定时器崩溃KotlinNullPointerException内部片段

我以这种方式在Kotlin中创建了Timer(java.util.Timer):

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) buttonStart.setOnClickListener({ val timer = Timer("schedule", true) timer.scheduleAtFixedRate(1000, 1000) { if (timerViewModel?.timerValue?.value!! > 0){ timerViewModel?.timerValue?.value = timerViewModel?.timerValue?.value!! - 1 activity.runOnUiThread { textViewTimer.text = timerViewModel?.timerValue?.value?.toString() } } else { cancel() } } }) } 

此代码在第五行崩溃,错误:

  kotlin.KotlinNullPointerException at com.dmitry.timer.views.TimerFragment$onViewCreated$1$$special$$inlined$scheduleAtFixedRate$1.run(Timer.kt:145) at java.util.Timer$TimerImpl.run(Timer.java:284) 

当我在activity创建计时器 – 它工作正常。 问题是什么?

它看起来像我textViewTimeractivity在这一行为空:

 activity.runOnUiThread{...} 

你确定你已经设置好了吗?

特别是,你不能依赖Fragment.getActivity() (只是Kotlin的activity )在创建后在任意点返回一个非空值。 因为您正在计时器中执行此操作,所以getActivity可能返回null。

另外:使用这样的嵌套lambda时,堆栈跟踪可能会令人困惑。 如果你仔细看看

 at com.dmitry.timer.views.TimerFragment$onViewCreated$1$$special$$inlined$scheduleAtFixedRate$1.run(Timer.kt:145) 

您可以在scheduleAtFixedRate之后看到$1 。 美元符号表示法经常用来指代匿名方法或lambda表达式,在这里我相信它是指你的定时器处理程序本身。

除了Myk Willis的回答之外,您还将安全呼叫( .? )以及NPE呼叫( !! )操作员组合在一起。

这意味着,如果timerViewModeltimerViewModel.timerValuetimerViewModel.timerValue.valuenull那么也可以导致你看到的NPE。 有效地否定使用安全呼叫运营商的好处。