Search code examples
javaandroidmultithreadingrunnableandroid-handler

Updating Destroyed Activity UI from Handler Runnable


The following code updates a TextView till a certain condition evaluates to false and then the Handler postDelayed is not called further.

However if the activity is destroyed, it'll try to update a null TextView, what is the right way to handle this? I know I could put a defensive null check on TextView but that is still not truly thread safe.

@Override
protected void onCreate(Bundle savedInstanceState) {
     Handler durationHandler = new Handler();
     durationHandler.postDelayed(updateSeekBarTime, 50);
}

private Runnable updateSeekBarTime = new Runnable() {
            public void run() {

                timeElapsed = mediaPlayer.getCurrentPosition();

                double timeRemaining = finalTime - timeElapsed;

                timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));

                if (timeRemaining >= 1000)
                    durationHandler.postDelayed(this, 200);
            }
        };

In other words the updateSeekBarTime can at any execution point try to access data members of an already destroyed activity, how to prevent that?


Solution

  • So after some code searching and reading blogs I found the answer in sample code of Communicating with the UI Thread

    Even though you can and should be removing callbacks from handler:

    handler.removeCallbacksAndMessages(null)
    

    But the above does not prevent the existing running Thread from accessing a destroyed Activity or its views.

    The answer I was looking for is WeakReference.

    Create a weak reference to the TextView or UI element that you'll access. The weak reference prevents memory leaks and crashes, because it automatically tracks the "state" of the variable it backs. If the reference becomes invalid, the weak reference is garbage-collected. This technique is important for referring to objects that are part of a component lifecycle. Using a hard reference may cause memory leaks as the value continues to change; even worse, it can cause crashes if the underlying component is destroyed. Using a weak reference to a View ensures that the reference is more transitory in nature.

    You should still check for null reference but now the view will be set to null by the active thread/runnable so you will not face a race-condition.