I have this code for my 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;
}
The app works fine the first time I navigate to this fragment, but if I return to the main page and navigate to this fragment again, the app has a 30% chance to crash, throwing java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getWidth()' on a null object reference
for the setText
line of the thread. I tried to use Thread.interrupt()
to stop the thread but it didn't work.
So what caused the crash and how can I solve it?
CodePudding user response:
You should take care ot two things here :
- sharing a variable between two threads
- updating UI out of the render thread / main thread
What you should do :
use thread safe variables like AtomicBoolean or a volatile boolean for the threadRunning
var... and a double checked locking or a Lock for verifying the value of the var
without this you have no guarantee that you update thread loop is not before the setText method when changing the threadRunning var value...
also, you'd better call super.onDestroyView() at the end of the onDestroyView method.
What you could do :
Dispatch the TextView update from the update thread to the main thread using one of the following possibility (not exhaustive)
- use a Handler associated with the main Looper
- use a coroutine or rxJava to dispatch the work to the right thread