Android View Binding in Thread 错误 NullPointerException
Android View Binding in Thread error NullPointerException
我已将我的代码切换到视图绑定,但现在我在线程中更新 UI 时遇到问题。该代码在合成语法中运行良好。我遇到错误:
java.lang.NullPointerException
at HomeFragment.getBind(HomeFragment.kt:25)
at HomeFragment.updateHomeUI$lambda-6(HomeFragment.kt:190)
at HomeFragment.$r8$lambdaK03ZbIZrY_5ngvcMBPsw15TPbw(Unknown Source:0)
at HomeFragment$$ExternalSyntheticLambda10.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:919)
我的代码:
class HomeFragment : Fragment(R.layout.fragment_home) {
private var _binding: FragmentHomeBinding? = null
private val bind get() = _binding!! // <-- line 25
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return bind.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
updateHomeUI()
}
private fun updateHomeUI() {
Thread {
while (bind.tvName != null) { // Stop the loop after changing the fragment
...
// Lots of UI update like this:
if (activity != null) (activity as MainActivity).runOnUiThread { bind.tvName?.text = str }
...
Thread.sleep(1000)
}
}.start()
}
当我切换到不同的片段时出现错误。如果我是对的,线程在 onDestroyView () 之后是 运行 并且绑定变为空。我想出了暂停 onDestroyView 直到 Thread 完成的想法,但我认为这不是最好的解决方案,因为它可能会停止整个应用程序。
override fun onDestroyView() {
super.onDestroyView()
threadStop = true
while (threadRunning) {
Thread.sleep(1)
}
_binding = null
}
private fun updateHomeUI() {
Thread {
threadRunning = true
threadStop = false
while (!threadStop) {
...
}
threadRunning = false
}
}
如何正确避免这个问题?
此致!
如果您放弃 !!
getter 并根据需要只使用可空类型和局部非空变量,您可能会发现这更容易。如果你有很多地方需要在循环内使用绑定,你可以在循环开始时获取它的非空值。
private fun updateHomeUI() {
Thread {
// this could also be while(true) since the calls just
// inside will break out when it goes null
while (_binding != null) { // Stop the loop after onDestroyView sets this to null
val binding = _binding ?: break
val a = activity as? MainActivity ?: break
// Lots of UI update like this:
a.runOnUiThread { binding.tvName.text = str }
...
Thread.sleep(1000)
}
}.start()
}
我不确定您现有的 bind.tvName != null
循环条件如何会 return false 而不是首先未通过 !!
检查。默认情况下,绑定 class 中的视图是非空的(除非它们不存在于所有布局排列中),因此这要么是正确的,要么会在 bind
[=21= 中失败] 当 _binding
为空时。
我已将我的代码切换到视图绑定,但现在我在线程中更新 UI 时遇到问题。该代码在合成语法中运行良好。我遇到错误:
java.lang.NullPointerException
at HomeFragment.getBind(HomeFragment.kt:25)
at HomeFragment.updateHomeUI$lambda-6(HomeFragment.kt:190)
at HomeFragment.$r8$lambdaK03ZbIZrY_5ngvcMBPsw15TPbw(Unknown Source:0)
at HomeFragment$$ExternalSyntheticLambda10.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:919)
我的代码:
class HomeFragment : Fragment(R.layout.fragment_home) {
private var _binding: FragmentHomeBinding? = null
private val bind get() = _binding!! // <-- line 25
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return bind.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
updateHomeUI()
}
private fun updateHomeUI() {
Thread {
while (bind.tvName != null) { // Stop the loop after changing the fragment
...
// Lots of UI update like this:
if (activity != null) (activity as MainActivity).runOnUiThread { bind.tvName?.text = str }
...
Thread.sleep(1000)
}
}.start()
}
当我切换到不同的片段时出现错误。如果我是对的,线程在 onDestroyView () 之后是 运行 并且绑定变为空。我想出了暂停 onDestroyView 直到 Thread 完成的想法,但我认为这不是最好的解决方案,因为它可能会停止整个应用程序。
override fun onDestroyView() {
super.onDestroyView()
threadStop = true
while (threadRunning) {
Thread.sleep(1)
}
_binding = null
}
private fun updateHomeUI() {
Thread {
threadRunning = true
threadStop = false
while (!threadStop) {
...
}
threadRunning = false
}
}
如何正确避免这个问题?
此致!
如果您放弃 !!
getter 并根据需要只使用可空类型和局部非空变量,您可能会发现这更容易。如果你有很多地方需要在循环内使用绑定,你可以在循环开始时获取它的非空值。
private fun updateHomeUI() {
Thread {
// this could also be while(true) since the calls just
// inside will break out when it goes null
while (_binding != null) { // Stop the loop after onDestroyView sets this to null
val binding = _binding ?: break
val a = activity as? MainActivity ?: break
// Lots of UI update like this:
a.runOnUiThread { binding.tvName.text = str }
...
Thread.sleep(1000)
}
}.start()
}
我不确定您现有的 bind.tvName != null
循环条件如何会 return false 而不是首先未通过 !!
检查。默认情况下,绑定 class 中的视图是非空的(除非它们不存在于所有布局排列中),因此这要么是正确的,要么会在 bind
[=21= 中失败] 当 _binding
为空时。