0

I have a fragment that launches a background thread to do some work and uses a handler callback to update some UI when the thread finishes its task.

public class CodeFragment extends Fragment implements View.OnClickListener, Handler.Callback {
  
  private CodeDataViewModel codeDataViewModel;
  private Handler uiHandler;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState){

        View view = inflater.inflate(R.layout.fragment_code, container, false);

        
        uiHandler = new Handler(Looper.getMainLooper(), this);

        return view;
    }

    @Override
    public boolean handleMessage(Message msg){

        if(msg.what == 0){

            BFResult result = (BFResult)msg.obj;

            codeDataViewModel.setOutput(result);

            runButton.setIcon(ResourcesCompat.getDrawable(requireActivity().getResources(), R.drawable.ic_baseline_play_arrow_24, null));
            runButton.setText(getString(R.string.run));
            codeDataViewModel.setShouldRun(true);

            if(result.errorCode != BFErrorCodes.UserAbort){
                ViewPager2 viewPager2 = getActivity().findViewById(R.id.view_pager);
                viewPager2.setCurrentItem(1);
            }
        }

        codeDataViewModel.setInterpreterThread(null);

        return true;
    }

The issue I have is when the screen rotates while the thread is still running, then, after the thread finishes executing and when handleMessage starts being executed I get the following exception in handleMessage at the line runButton.setIcon(...)

FATAL EXCEPTION: main
java.lang.IllegalStateException: Fragment CodeFragment{7f397b9} (ea45dd9d-5419-4d22-8f56-11c7fed9f3bd) not attached to an activity.
at androidx.fragment.app.Fragment.requireActivity(Fragment.java:928)
at com.sandeept.brainfkinterpreter.fragments.CodeFragment.handleMessage(CodeFragment.java:117)

Now, I know this is because the activity and the fragments are recreated when a configuration change occurs. And because the handleMessage function being executed is of the old fragment that is now no longer attached to the activity there is a run time error.

What I don't know is how to fix this. I thought about using setRetainInstance(true), but this has been deprecated since the introduction of view models. I don't know how view models are going to be helpful in this case.

So, how do I handle this issue?

  • Rather than ancient, low-level approaches like `Handler` and `Messenger`, use a modern reactive framework, such as `LiveData` or RxJava. FWIW, I demonstrate `LiveData` in a `ViewModel` in [this chapter](https://commonsware.com/Jetpack/pages/chap-threads-001.html) of [this free book](https://commonsware.com/Jetpack/). – CommonsWare Feb 15 '23 at 22:44

0 Answers0