启动片段的后台线程时,应用程序随机崩溃
App randomly crashes when starting background thread of a fragment
我的片段有以下代码:
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
txtAngle = view.findViewById(R.id.textView_angle);
updateTextThread = new Thread(new Runnable() {
@Override
public void run() {
while (threadRunning) {
txtAngle.setText("1");
}
}
});
threadRunning = true;
updateTextThread.start();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
threadRunning = false;
}
应用程序在我第一次导航到这个片段时工作正常,但如果我 return 到主页并再次导航到这个片段,应用程序有 30% 的机会崩溃,抛出 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getWidth()' on a null object reference
用于线程的 setText
行。我尝试使用 Thread.interrupt()
来停止线程,但它没有用。
那么是什么导致了崩溃,我该如何解决?
你应该注意两件事:
- 在两个线程之间共享一个变量
- 更新 UI 渲染线程/主线程
你应该做什么:
使用线程安全变量,如 AtomicBoolean 或 volatile boolean 作为 threadRunning
var...,并使用双重检查锁定或 Lock 来验证 var
的值
如果没有这个,你无法保证在更改 threadRunning var 值时更新线程循环不在 setText 方法之前...
另外,你最好在 onDestroyView 方法的最后调用 super.onDestroyView()。
你能做什么:
使用以下可能性之一(并非详尽无遗)将 TextView 更新从更新线程分派到主线程
- 使用与主 Looper 关联的 Handler
- 使用协程或 rxJava 将工作分派到正确的线程
我的片段有以下代码:
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
txtAngle = view.findViewById(R.id.textView_angle);
updateTextThread = new Thread(new Runnable() {
@Override
public void run() {
while (threadRunning) {
txtAngle.setText("1");
}
}
});
threadRunning = true;
updateTextThread.start();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
threadRunning = false;
}
应用程序在我第一次导航到这个片段时工作正常,但如果我 return 到主页并再次导航到这个片段,应用程序有 30% 的机会崩溃,抛出 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getWidth()' on a null object reference
用于线程的 setText
行。我尝试使用 Thread.interrupt()
来停止线程,但它没有用。
那么是什么导致了崩溃,我该如何解决?
你应该注意两件事:
- 在两个线程之间共享一个变量
- 更新 UI 渲染线程/主线程
你应该做什么:
使用线程安全变量,如 AtomicBoolean 或 volatile boolean 作为 threadRunning
var...,并使用双重检查锁定或 Lock 来验证 var
如果没有这个,你无法保证在更改 threadRunning var 值时更新线程循环不在 setText 方法之前...
另外,你最好在 onDestroyView 方法的最后调用 super.onDestroyView()。
你能做什么:
使用以下可能性之一(并非详尽无遗)将 TextView 更新从更新线程分派到主线程
- 使用与主 Looper 关联的 Handler
- 使用协程或 rxJava 将工作分派到正确的线程