user3064141
user3064141

Reputation: 407

Android: can't access view from within Thread

I am trying to write a simple app example that will run through a for loop incrementing its counter by 1 each time and then use the current value of the counter i to update the view and print out: "i = #" I get an error saying you can't update a view that was not created in that thread. i tried to address this by inflating the view from within the thread and also by creating a new TextView and calling "setContentView(myTextView)". but neither of these fixed the problem. I tried a different version that used an AsyncTask but I got stuck on how to divid up the code into each of AsyncTask's methods. could someone help me see how to do this as it has shown me I am missing in my understanding on this point. Thanks Edward ps. the commented out lines for the inflater and the setContentView are from my attempts to fix it.

my code from my original attempt that is trying to update my TextView "myTextView" in the main layout for the app:

public void loopForever(View view) {

        Thread thread = new Thread(){
            public void run(){

                // LayoutInflater inflater = null;     
                // inflater.inflate(R.layout.activity_main, null);

                TextView myTextView;
                myTextView = (TextView) findViewById(R.id.myTextView);
                // setContentView(myTextView)

                for(int i = 0; i < 1000; i++){
                    myTextView.setText("i = " + i);
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
}

Upvotes: 1

Views: 1809

Answers (3)

user3229557
user3229557

Reputation:

As the other users have stated, you cannot update user interface elements from any thread other than the main thread. You should use the view class post() or postDelayed() method, your code should look something like this:

for(int i = 0; i < 1000; i++){

    myTextView.postDelayed(new Runnable(){

        public void run(){

           myTextView.setText("i = " + i);
        }  

    }, 1000);
}

here is a link: http://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)

You might also want to take a look at android async task class http://developer.android.com/reference/android/os/AsyncTask.html

Upvotes: 1

Bismarck
Bismarck

Reputation: 96

You can only access View elements from within the UI Thread (Activities, fragments etc. callbacks). You could either switch to an Asynctask and do the UI changes via the postexecute or publish progress callbacks (http://developer.android.com/reference/android/os/AsyncTask.html), or use runOnUiThread, example:

public void loopForever(View view) {

    Thread thread = new Thread(){
        public void run(){
            for(int i = 0; i < 1000; i++){
                activity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                  (TextView) activity.findViewById(R.id.myTextView).setText("i = " + i);
                 }
                });
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    thread.start();
}

Upvotes: 1

jacobianism
jacobianism

Reputation: 226

You must update User Interface (UI) elements, like your TextView, from the "UI Thread". You cannot update them from other threads such as the one you have made.

This Android lesson might be useful to read:

Every app has its own special thread that runs UI objects such as View objects; this thread is called the UI thread. Only objects running on the UI thread have access to other objects on that thread. Because tasks that you run on a thread from a thread pool aren't running on your UI thread, they don't have access to UI objects. To move data from a background thread to the UI thread, use a Handler that's running on the UI thread.

If you use AsyncTask, you can override the onProgressUpdate(Progress...) method to update your TextView. onProgressUpdate(Progress...) deliberately runs on the UI thread to allow this.

Upvotes: 0

Related Questions