Ted pottel
Ted pottel

Reputation: 6983

how can I chnage a TextViews text from a thread?

I'm trying to write code to pull a server every second for updated messages. The messages then get displayed in a text view. If I do not change the text in the text view it runs fine. It will crash if I try to change the textview on the thread. IF i change it not on the thread works fine.

I'm assuming the thread cannot access the main threads memory? How can I set the text in the view with the text just loaded over the internet?

In the code below I have a thread that does a endless loop with a sleep. It calls a method called SendMessage. Send Message loads in text over the internet and at the end tries to update the View with it. It causes a exception when this happens.

code:

public class cChat extends cBase  implements OnClickListener {
    /** Called when the activity is first created. */
      TextView mUsers; 
      TextView mComments; 
      int i=0;

    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.chat);

            mUsers=( TextView) findViewById(R.id.viewusers);;
            mComments=( TextView) findViewById(R.id.viewchats);;

          Thread thread = new Thread()
          {
              @Override
              public void run() {
                  try {
                      int t=0;
                      while(true) 
                      {
                          SendMessage();
                          sleep(1000*5);
                          t++;
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          };

          thread.start();

        }


       public void onClick(View v) {


           } // end function



        // send a uypdate message to chat server 
        // return reply in string
        void SendMessage()
        {


            try {


            URL url = new URL("http://50.63.66.138:1044/update");
               System.out.println("make connection");

               URLConnection conn = url.openConnection();
               // set timeouts to 5 seconds
               conn.setConnectTimeout(1000*5);
               conn.setReadTimeout(5*1000);
               conn.setDoOutput(true);
               BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));


            //   String line;
               String strUsers=new String("");
               String strComments=new String("");
               String line=new String();
               int state=0;
               while ((line= rd.readLine()  ) != null) {
                 switch(state){
                 case 0:
                   if ( line.contains("START USER"))
                     state=1;
                   if ( line.contains("START COMMENTS"))
                     state=2;
                   break;
                 case 1:
                   if ( line.contains("END USER"))
                         state=0;
                   else
                   {
                   strUsers+=line;
                   strUsers+="\n";
                   }
                   break;
                 case 2:
                       if ( line.contains("END COMMENTS"))
                             state=0;
                       else {
                       strComments+=line;
                       strComments+="\n";
                       }
                       break;
                 } // end switch   
               } // end loop

      // the next line will cause a exception
               mUsers.setText(strUsers);
               mComments.setText(strComments);

        } catch (Exception e) {
             i++; // use this to see if it goes here in debugger  
            //   System.out.println("exception");
           //    System.out.println(e.getMessage());
           }

        } // end methed
}

Upvotes: 0

Views: 133

Answers (5)

ixx
ixx

Reputation: 32271

You can use a handler to post tasks (Runnables) to the UI/Main Thread:

private Handler handler = new Handler();

//...

Thread thread = new Thread()
{
@Override
public void run() {
    try {
        int t=0;
        while(true) 
        {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    SendMessage();
                }
            });

            sleep(1000*5);
            t++;
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
};

Upvotes: 0

Eight
Eight

Reputation: 4284

the Andoid UI toolkit is not thread-safe. So, you  
must not manipulate your UI from a worker thread    

To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:

you can also use AsyncTask.

see this tutorial on process and threads in android.

Upvotes: 0

ρяσѕρєя K
ρяσѕρєя K

Reputation: 132972

use runOnUiThread as

 YOUR_CURRENT_ACTIVITY.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
         // the next line will cause a exception
           mUsers.setText(strUsers);
           mComments.setText(strComments);
            //....YOUR UI ELEMENTS
         }
        });

EDIT : see doc runOnUiThread

Upvotes: 3

Arun George
Arun George

Reputation: 18592

Try using a Service to continuously pull/send data to server. This will reduce the load on your UI-Thread.

Upvotes: 0

K-ballo
K-ballo

Reputation: 81349

You can't touch an UI widget from a thread different than the one used to create it (the UI thread). But if you have a reference to the Activity, you can simply do:

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        mUsers.setText(strUsers);
        mComments.setText(strComments);
    }
});

which would require strUsers to be accessible by the anonymous class. For that you can simply do:

final String finalUseres = strUsers;

and use finalUsers within run().

Upvotes: 0

Related Questions