corbin
corbin

Reputation: 1

How to update UI via Handler

So, I am getting an error that I am updating the UI from the wrong thread. This of course was not my intention. My case is quite long, but I will try to do it justice with code snippets. My end goal is to run an expensive task in a separate thread and post update that happen along the way and at the end to my listView.

public class test extends Activity {

   private ArrayAdapter<String> _mOutArrayAdapter;
   private ListView _mOutView;
   private EditText _mCmdEditText;
   private Button _mRunButton;
   private Interpreter _interpreter;

   // Need handler for callbacks to the UI thread
   public final Handler _mHandler = new Handler() {
    public void handleMessage(Message msg) {
        _mOutArrayAdapter.add(msg.getData().getString("text"));
    };
   };

   // Create runnable for posting
   final Runnable mUpdateResults = new Runnable() {
       public void run() {
           updateResultsInUi();
       }
   };

   /** Called when the activity is first created. */
    @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       _interpreter = new Interpreter(true);

       _mOutView = (ListView)findViewById(R.id.out);
       _mCmdEditText = (EditText)findViewById(R.id.edit_command);
       _mRunButton = (Button)findViewById(R.id.button_run);

       _mOutArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
       _mOutView.setAdapter(_mOutArrayAdapter);
       _mOutArrayAdapter.clear();
       _interpreter.setOutputAdapter(_mOutArrayAdapter);

       Thread t = new Thread() {
            public void run() {
               _mResults = _interpreter.executeExpression("startup;",_mHandler);
               _mHandler.post(mUpdateResults);
           }
       };
       t.start();

   ); 

And then inside inpterpreter I do this:

public class Interpreter 
{

    private static Handler _mHandler;

    public String executeExpression(String expression, Handler handler)
    {  
        _mHandler = handler;

        //Do a bunch of stuff that sometimes calls displayText from this class or from others

        return answer;
    }

    public void displayText(String text)
    {
        Message msg = new Message();
        Bundle bndl = new Bundle();
        bndl.putString("text", text);
        msg.setData(bndl);
        _mHandler.dispatchMessage(msg);
    }
}

The display of the final answer works. And the dispatchMessage is ending up triggering handleMessage, but it throw an error that I cannot modify the UI from outside of the UI thread which I know is illegal. So, what am I doing wrong?

Thanks!

Upvotes: 0

Views: 1913

Answers (3)

jeet
jeet

Reputation: 29199

Handler's post method requires a Runnable object in parameter, and scheduling execution of that runnable block. Instead you can use Handler.sendEmptyMessage() or Handler.sendMessage() to send a message to Handler. SO change your code to following:

Thread t = new Thread() {
            public void run() {
               _mResults = _interpreter.executeExpression("startup;",_mHandler);
                Message msg= _mHandler.obtainMessage();
                msg.obj= _mResults;
               _mHandler.sendMessage(msg);
           }
       };

Upvotes: 1

CLo
CLo

Reputation: 3730

_mHandler.dispatchMessage(msg);

dispatchMessage() causes the Handler to be run on the current thread. http://developer.android.com/reference/android/os/Handler.html

dispatchMessage(Message msg)

Handle system messages here.

You should be using _mHandler.sendMessage(msg); It will put the message on the queue to be run by the Thread that declared the Handler.

sendMessage(Message msg)

Pushes a message onto the end of the message queue after all pending messages before the current time.

Upvotes: 3

Yoni Samlan
Yoni Samlan

Reputation: 38065

I would strongly suggest you stick with an AsyncTask (or one of the droid-fu versions if you need rotation/background support) unless you know what you're getting into. It'll help you cleanly keep track of what code is running in your UI thread and what code is in the background task, and save you a lot of confusion that dealing with Threads and Handlers yourself can cause.

Upvotes: 2

Related Questions