Interaction with user on Thread cause my app crash

76 views Asked by At

My app crashes if TextView.setText is inside Thread:
NOTE: The following class is inside of MainActivity.

private class StreamThread extends Thread {
    public StreamThread() {

    }

    public void run() {
        byte[] buffer = new byte[1024];
        int bytes;
        while (true) {
            try {
                bytes = mmInStream.read(buffer);
                String message = new String(buffer, 0, bytes);
                //THIS IS IMPORTANT, READ THIS PLEASE
                //I tested many times my app to find the problem, and I found, my app crashes when TextView.setText() is executed

                //Here starts the problem
                ((TextView) findViewById(R.id.textView)).setText(message);
            } catch (IOException e) {
                break;
            }
    }

}
3

There are 3 answers

0
hgross On BEST ANSWER

This should do the trick:

private class StreamThread extends Thread {
    public StreamThread() {}

    public void run() {
        byte[] buffer = new byte[1024];
        int bytes;
        while (true) {
            try {
                bytes = mmInStream.read(buffer);
                String message = new String(buffer, 0, bytes);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ((TextView) findViewById(R.id.textView)).setText(message);
                    }
                });
            } catch (IOException e) {
                break;
            }
        }
    }
}

Sooo, what was wrong? Android's UI is single threaded. This means you are not allowed to change the ui from another thread than the ui thread. You can post changes to the ui thread using the runOnUiThread-Method or using a Handler.

0
AudioBubble On

Threads are designed for execute code by separated allowing another codes execute to the same time. Unafortunately Threads are not compatible with UI, but I have a solution.

runOnUiThread(new Runnable() {
    @Override
    public void run () {
        //Some stuff that needs to interact with the user (UI).
    }
}
0
Dani Meana On

You must update visual components in the ui thread. For your purpose you should use an AsyncTask, Service or a Runnable which runs in the ui thread.

For example, you use an AsyncTask like in the following code:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textview = (TextView) findViewById(R.id.textView);
        new StreamAsyncTask(textview).execute();
    }

    private class StreamAsyncTask extends AsyncTask<Void, String, Void> {

        private TextView textview;

        public StreamAsyncTask(TextView textview) {
            this.textview = textview;
        }

        @Override
        protected Void doInBackground(Void... voids) {
            byte[] buffer = new byte[1024];
            int bytes;
            while (true) {
                try {
                    bytes = mmInStream.read(buffer);
                    String message = new String(buffer, 0, bytes);
                    publishProgress(message);
                } catch (IOException e) {
                    break;
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            textview.setText(values[0]);
        }
    }
}

Or you can use the Activity's method runOnUiThread:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        ((TextView) findViewById(R.id.textView)).setText(message);
    }
});

The last way is easier to understand but the first one is more flexible. Read about AsyncTasks: http://developer.android.com/reference/android/os/AsyncTask.html