Android development
view hierarchy
UI thread
concurrency
multithreading

Android Only the original thread that created a view hierarchy can touch its views.

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Android developers often encounter several threading rules and constraints when building applications. One such rule that often puzzles both novice and experienced developers alike is: "Only the original thread that created a view hierarchy can touch its views." This behavior is central to maintaining UI thread safety in Android and avoiding common pitfalls like race conditions and UI inconsistencies.

Understanding the UI Thread

In Android, the UI thread (also known as the main thread) is responsible for handling all user interface operations. This includes drawing views on the screen, responding to user interactions, and managing UI updates. The significance of the UI thread stems from the need to maintain smooth scrolling, quick user feedback, and overall responsive UI behaviors.

Why UI Thread Isolation?

The rule "Only the original thread that created a view hierarchy can touch its views" is crucial to prevent concurrent modifications that could otherwise lead to unpredictable behavior. Accessing or modifying UI components from a non-UI thread risks corrupting the view hierarchy and causing app crashes.

To understand why this rule exists, consider the following points:

  • Thread Safety: Android UI toolkit is not thread-safe. Concurrent access by multiple threads could lead to UI inconsistencies or crashes.
  • Performance: Synchronizing multiple threads for UI updates could degrade performance significantly due to the overhead of context switching and lock management.

Examples and Solutions

Example Scenario

Imagine a scenario where a background thread fetches some data from the internet and attempts to update a TextView with this new data:

java
1package com.example.myapp;
2
3import android.widget.TextView;
4// other imports
5
6public class NetworkTask extends Thread {
7    private TextView textView;
8
9    public NetworkTask(TextView tv) {
10        this.textView = tv;
11    }
12
13    @Override
14    public void run() {
15        // Simulating network call
16        String data = fetchDataFromNetwork();
17
18        // Attempt to update TextView (this will crash)
19        textView.setText(data);
20    }
21}

In this example, trying to set the text from a background thread will throw a CalledFromWrongThreadException, as you're violating the rule.

Correct Approach

Using Activity.runOnUiThread()

One common approach to updating the UI from a background thread is to use the runOnUiThread() method:

java
1@Override
2public void run() {
3    final String data = fetchDataFromNetwork();
4
5    // Update the UI on the main thread
6    textView.post(new Runnable() {
7        @Override
8        public void run() {
9            textView.setText(data);
10        }
11    });
12}

Using Handler

Another prevalent method is using Handler, which can post a runnable back to the UI thread:

java
1private Handler handler = new Handler(Looper.getMainLooper());
2
3@Override
4public void run() {
5    final String data = fetchDataFromNetwork();
6
7    handler.post(new Runnable() {
8        @Override
9        public void run() {
10            textView.setText(data);
11        }
12    });
13}

Modern Solutions

AsyncTask (deprecated in newer Android versions)

For simple background operations, developers often used AsyncTask. However, it has been deprecated due to its limitations:

java
1new AsyncTask<Void, Void, String>() {
2    @Override
3    protected String doInBackground(Void... voids) {
4        return fetchDataFromNetwork();
5    }
6
7    @Override
8    protected void onPostExecute(String data) {
9        textView.setText(data);
10    }
11}.execute();

LiveData and ViewModel

In modern Android development, using LiveData and ViewModel is encouraged for managing UI-related data in a lifecycle-conscious way:

java
1class DataViewModel : ViewModel() {
2    private val data: MutableLiveData<String> = MutableLiveData()
3
4    fun fetchData() {
5        // simulate fetching from network
6        data.postValue(fetchDataFromNetwork())
7    }
8
9    fun getData(): LiveData<String> {
10        return data
11    }
12}
13
14// In Activity or Fragment
15viewModel.getData().observe(this, Observer { newData ->
16    textView.setText(newData)
17})

Summary Table

Below is a table summarizing the main points regarding accessing UI components from different threads:

ScenarioSolution
Direct UI updates from background threadThrows CalledFromWrongThreadException
Use runOnUiThread() or TextView.post()Safe: Executes code block on the UI thread
Use Handler from background threadsSafe: Posts UI update tasks to main thread
Use AsyncTask for background operationsSafe, but deprecated. Consider other options
Modern approach with LiveData and ViewModelRecommended: Lifecycle-aware and testable

Conclusion

Understanding and respecting the rule "Only the original thread that created a view hierarchy can touch its views" is critical for Android developers to ensure seamless and responsive application UI. By leveraging various techniques and modern architecture components, one can manage threading complexities while adhering to best practices for apps' UI updates. Always endeavour to adhere to these principles to prevent unpredictable behaviors and to create a robust user experience.


Course illustration
Course illustration

All Rights Reserved.