Why Your TextView or Button Text Is Not Updating

Understand Why Changing View Text Does Not Work or is Delayed

When changing the text for a TextView using the setText method new Android developers sometimes fail to understand why it does not appear to work. The text not updating also applies to other Views as well, such as the EditView and Button, why this happens is explained. This article is also useful in helping to understand why the User Interface (UI) in your Android App might not be as responsive as expected. The underlying problem is the same. So if you are trying to find out why your setText() on EditText, TextView, Button, etc. is not working as intended, or you UI is sluggish read on, it includes a work around to help you out.

Not All Android Code Executes Immediately

When changing the TextView text this code is second nature to all Android developers:

For those new to programming the above is equivalent to these two lines but saves having to declare the TextView object:

When setText(“New Text”) is run the text is not updated immediately. Android is an event based system. Something happens on the device (the screen is touched, a key is pressed, a call comes in, etc.) and Android raises an event. An App is notified of an event and when one occurs that it needs to respond to it does so, often running the code that you have written. Your App runs its code in a loop under the control of the Android Operating Systems (OS). This code loop is referred to as the App’s thread of execution. There is only one thread and it is responsible for both running the App code and updating the display. The setText call posts a message to update the display, so the update does not happen immediately. Once remaining App code has run the UI messages are processed, then the text changes. A running App’s execution thread can be viewed as shown in this simplified diagram.

App Thread Loop

What this means is that changes to the UI can get delayed, and in some cases not appear to occur, when the running App code is doing a time intensive task, for example looping calculations, complex queries to large databases, accessing network resources etc. A common scenario in not seeing the UI update is along these lines:

What happens is that the Finished message is seen but the progress messages are not. It is easy to reproduce this scenario by creating a new simple App, dropping a Button on to the default Activity and then adding the above code with a call to sleep() in the loop. Here’s an example layout and activity code to reproduce the problem:

Application Not RespondingIf the UI is prevented from updating for more than about five seconds then what is known as an ANR (Application Not Responding) error occurs. The user may think the App has crashed completely and force close it, and then probably remove it from the device. Humans can detect systems responding down to tens of milliseconds, at about one tenth of a second pauses begin to degrade the experience of using a program. If no feedback is given for a few seconds users can become annoyed. It is easy to get the ANR error with the above code, increase the number for the test in the if statement from six to twelve (if(++number_processed>12)), run the App and punch the button several times.

A Helper Class Is Available to Run Another Thread

What is needed is a way to process the UI messages so that the display updates and still runs the intensive code. This is done by getting the App to define another execution thread on which the intensive code is executed. Thus stopping the main thread from appearing to lock up when UI updates fail. This is represented by this diagram:

Android App with Additional Thread

Android has a built in class to make running intensive code easy, the AsyncTask, it is covered in the tutorial article, The Android AsyncTask Class Helps Avoid ANRs. Whenever a section of code is going to take some time to execute, maybe a second or more, then the use of AsyncTask is recommended. However, it can appear overkill when all you want to do is update a TextView to provide feedback before executing some code that may take a second or two.

Example Code That Has Variable Execution Time

Let us look at another example and improve it to provide appropriate feedback. The following code is going to check whether or not a long integer is a primary number or not. (We could have used the Java BigInteger class but this routine is used as an example.) A prime number is any number that can be divided by itself and the number one, so the sequence begins 2, 3, 5, 7, 11, 13, 17, 19, 23, etc. and goes on for infinity. Routines to perform a primality test are well established and are usually based upon the Sieve of Eratosthenes.This function was derived from the script at Prime Curios! Primality Test web page.

For most numbers the routine executes extremely quickly, however, a long integer can have up to 19 digits. If a 19 digit number is a prime then the inner loop can run several million times and a long pause in the program occurs. Here is the layout and code for a primality testing App.

Primality Test RunningMost numbers typed in fail the test immediately, as most are not primes, and there is no problem with the response of the App. Likewise for small prime numbers, such as the eggshell number 77345993. (Why eggshell? Well if that number is typed into a desktop calculator with a Liquid Crystal Display, LCD, and the calculator is turned upside down then it sort of reads EGGSHELL.)

Now try a really big prime number, a web search will reveal plenty, how about nineteen ones, 1111111111111111111, strangely this is a prime number. Notice that it takes a few seconds for the routine to determine that it is a prime number. If we add tv.setText(“Checking please wait.”) at the beginning of the CheckPrimeClick we get the same problem as our sleep example. The UI update is blocked by the looping code.

Use A Timer and Handler To Provide Feedback

A useful solution to this problem without using the AsyncTask task class is to introduce a very small delay between calling tv.setText and running the isPrime routine. During this delay the main thread continues and thus gets to up date the interface. The delay cannot be a Java sleep delay because that stops the program execution dead. Instead a Timer is used. When the TimerTask is run after the small delay it sends an empty message that is caught by a Handler and the Handler’s Callback then executes the call to isPrime. A Timer is delared like this, Timer timer=new Timer(). The Android in built Handler class is used (and the associated Handler.Callback so that we do not need to implement our own callback). The Callback is declared and code calling isPrime moved into it:

The Handler can be declared in the onCreate to use the Callback, handler = new Handler(callback). The TimerTask simply posts an empty message using the Handler.

Primality Test CheckingThe click handler schedules the delay with timer.schedule(new SmallDelay(), 100). The result is that the UI gets the chance to update whilst the code that was previously blocking the update still executes, after being kicked off by the timer. A straightforward solution for when a quick UI update is required when code can potentially hog the main thread for a short while. Here is the complete code:

Do not forget that for more complex UI feedback, including showing an active progress bar then the AsyncTask solution is better.

Leave a Reply

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

Human Verification: In order to verify that you are a human and not a spam bot, please enter the answer into the following box below based on the instructions contained in the graphic.