Zakaria
Zakaria

Reputation: 73

Using handler to change ui, still "only the original thread that created a view hierarchy can touch its views." error

I have two threads, two handlers. From thread i check a random number and send result to handle to update ui. But i am getting the error "only the original thread that created a view hierarchy can touch its views.". I searched some articles, they tell to use handler. I am doing that, yet can not avoid the errors.

After some checking, I found that it crashes when A sends the result. In case of B, it works

Also, can i use one handler for two thread?

public class MainActivity extends Activity implements View.OnClickListener{
    Button start;
    TextView status_B, status_A;
    Boolean isRunning;
    Thread Athread, Bthread;
    int a, b;
    Handler a_Handler, b_Handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Initialize variables
        start = (Button) findViewById(R.id.button);
        start.setOnClickListener(this);
        status_B = (TextView) findViewById(R.id.textView);
        status_A = (TextView) findViewById(R.id.textView1);

        a_Handler = new Handler() {
            public void handleMessage(Message msg)
            {
                int number = msg.getData().getInt("number");
                String winner = msg.getData().getString("winner");
                start.setEnabled(true);
                isRunning = false;
                status_A.setText(winner + number);
            }
        };
        b_Handler = new Handler() {
            public void handleMessage(Message msg)
            {
                int number = msg.getData().getInt("number");
                String winner = msg.getData().getString("winner");
                start.setEnabled(true);
                isRunning = false;
                status_B.setText(winner + number);
            }
        };
    }

    @Override
    protected void onStart() {
        super.onStart();
        isRunning = false;        
    }


    @Override
    public void onClick(View v) {
        start.setEnabled(false);
        status_B.setText("Guessing...");
        if (!isRunning)
        {
            Athread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (isRunning)
                    {
                        try
                        {
                            Athread.sleep(1000);
                        }
                        catch (InterruptedException e)
                        {
                            e.printStackTrace();
                        }
                        a = (int) (Math.random()*1000);
                        System.out.println("a "+ a);
                        if(a%7 == 0) {
                            isRunning = false;
                            Bundle bundle = new Bundle();
                            bundle.putString("winner", "A");
                            bundle.putInt("number", a);
                            Message msg = a_Handler.obtainMessage();
                            msg.setData(bundle);
                            a_Handler.handleMessage(msg);
                        }
                    }
                }
            });
            Bthread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(isRunning)
                    {
                        try
                        {
                            Bthread.sleep(1000);
                        }
                        catch (InterruptedException e)
                        {
                            e.printStackTrace();
                        }
                        b = (int) (Math.random()*1000);
                        System.out.println("b "+ b);
                        if(b%7 == 0) {
                            isRunning = false;
                            Bundle bundle = new Bundle();
                            bundle.putString("winner", "B");
                            bundle.putInt("number", b);
                            Message msg = b_Handler.obtainMessage();
                            msg.setData(bundle);
                            b_Handler.sendMessage(msg);
                        }
                    }
                }
            });
            isRunning = true;
            Athread.start();
            Bthread.start();
        }
    }
}

Upvotes: 0

Views: 418

Answers (1)

Jose Rodriguez
Jose Rodriguez

Reputation: 10202

You need put your code to modify views on UI thread:

a_Handler = new Handler() {
        public void handleMessage(Message msg)
        {
            final int number = msg.getData().getInt("number");
            final String winner = msg.getData().getString("winner");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    start.setEnabled(true);
                    status_A.setText(winner + number);
                }
            });
            isRunning = false;
        }
    };
    b_Handler = new Handler() {
        public void handleMessage(Message msg)
        {
            final int number = msg.getData().getInt("number");
            final String winner = msg.getData().getString("winner");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    start.setEnabled(true);
                    status_B.setText(winner + number);
                }
            });
            isRunning = false;
        }
    };

Upvotes: 1

Related Questions