Updating Android UI from Background Threads

In Android development, it’s common to perform time-consuming operations on background threads to avoid blocking the main thread and ensure a responsive user interface. However, when updating the UI from these background threads, you may encounter the "Only the original thread that created a view hierarchy can touch its views" error. This tutorial will explain why this happens and provide solutions to update the Android UI safely from background threads.

Understanding the Problem

In Android, each application has its own main thread (also known as the UI thread), which is responsible for handling user interactions and updating the UI. When you create a view hierarchy in an Activity’s onCreate method, it’s associated with this main thread. However, when you try to update the UI from a background thread, Android throws a CalledFromWrongThreadException, because only the original thread that created the view hierarchy can touch its views.

Solution 1: Using runOnUiThread

One way to solve this problem is by using the runOnUiThread method provided by the Activity class. This method allows you to execute a Runnable on the main thread, which can then update the UI safely. Here’s an example:

public void run() {
    int pos = 0;
    int total = mp.getDuration();
    while (mp != null && pos < total) {
        try {
            Thread.sleep(1000);
            pos = appService.getSongPosition();
        } catch (InterruptedException e) {
            return;
        } catch (Exception e) {
            return;
        }
        // Update the UI on the main thread
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progress.setProgress(pos);
                String time = String.format("%d:%02d",
                        TimeUnit.MILLISECONDS.toMinutes(pos),
                        TimeUnit.MILLISECONDS.toSeconds(pos) % 60);
                currentTime.setText(time);
            }
        });
    }
}

Solution 2: Using Handlers

Another way to update the UI from a background thread is by using Handlers. A Handler allows you to send and process messages (Runnable or Message objects) between threads. Here’s an example:

private Handler handler = new Handler(Looper.getMainLooper());

public void run() {
    int pos = 0;
    int total = mp.getDuration();
    while (mp != null && pos < total) {
        try {
            Thread.sleep(1000);
            pos = appService.getSongPosition();
        } catch (InterruptedException e) {
            return;
        } catch (Exception e) {
            return;
        }
        // Update the UI on the main thread using a Handler
        handler.post(new Runnable() {
            @Override
            public void run() {
                progress.setProgress(pos);
                String time = String.format("%d:%02d",
                        TimeUnit.MILLISECONDS.toMinutes(pos),
                        TimeUnit.MILLISECONDS.toSeconds(pos) % 60);
                currentTime.setText(time);
            }
        });
    }
}

Solution 3: Using Kotlin Coroutines

If you’re using Kotlin, you can use coroutines to simplify your code and update the UI safely. Here’s an example:

lifecycleScope.launch {
    withContext(Dispatchers.Default) {
        // Background processing...
    }
    // Update the UI on the main thread
    progress.progress = pos
    val time = String.format("%d:%02d",
            TimeUnit.MILLISECONDS.toMinutes(pos),
            TimeUnit.MILLISECONDS.toSeconds(pos) % 60)
    currentTime.text = time
}

Best Practices

When updating the UI from background threads, keep the following best practices in mind:

  • Always update the UI on the main thread to avoid CalledFromWrongThreadException.
  • Use runOnUiThread or Handlers to execute Runnables on the main thread.
  • Keep the background processing code separate from the UI update code for better readability and maintainability.
  • Avoid blocking the main thread with time-consuming operations; instead, perform them on background threads.

By following these guidelines and using the solutions provided in this tutorial, you can safely update your Android app’s UI from background threads and ensure a responsive user experience.

Leave a Reply

Your email address will not be published. Required fields are marked *