Android. Ошибка "Only the original thread that created a view hierarchy can touch its views."

февраля
14
2012
Метки: android handler java

Android-архитектура построена таким образом, что визуальные компоненты могут изменять свое состояние только из своего потока. То есть, если Вы в своем потоке вызовите к примеру следующий код:


new Thread() {
	public void run() {
		textView.setText("I'm text view");
	}
}.start();

то получите сообщение об ошибке:


android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Эту ошибку можно исправить, используя Handler. Этот способ является наиболее приемлемым. В Вашем приложении Вам необходимо инициализировать поле handler, например в onCreate методе:


private Handler handler;

@Override
public void onCreate(Bundle savedInstanceState) {
        // some code
	handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			String text = (String) msg.obj;
			textView.setText( text );
		}
	};
}

А вызов textView.setText("I'm text view") заменить на:


Message msg = new Message();
msg.obj = text;
handler.sendMessage(msg);

Второй способ - привязка к Handler нового потока. Это более ресурсоемкий способ. Замените вызов textView.setText("I'm text view") на:


Handler handler = new Handler(getBaseContext().getMainLooper());
handler.post( new Runnable() {
	@Override
	public void run() {
		textView.setText("I'm text view");
	}
} );

Приложение, демонстрирующее оба способа:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    
    <Button
        android:id="@+id/btn" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Click Me!"/>

</LinearLayout>

CustomEventsActivity.java

package com.seostella.customevents;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class CustomEventsActivity extends Activity implements
		View.OnClickListener {
	private TextView textView;
	private Button btn;
	private Handler handler;

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

		textView = (TextView) findViewById(R.id.textView);
		btn = (Button) findViewById(R.id.btn);
		btn.setOnClickListener(this);

		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				String text = (String) msg.obj;
				textView.setText(text);
			}
		};

	}

	@Override
	public void onClick(View arg0) {
		new Thread() {
			@Override
			public void run() {
				String text = "I'm text view";
				setTextHandler(text);
				// setTextPost(text);
			}
		}.start();
	}

	private void setTextHandler(final String text) {
		Message msg = new Message();
		msg.obj = text;
		handler.sendMessage(msg);
	}

	private void setTextPost(final String text) {
		Handler handler = new Handler(getBaseContext().getMainLooper());
		handler.post(new Runnable() {
			@Override
			public void run() {
				textView.setText(text);
			}
		});
	}
}

Напишите первое сообщение!

Вы должны войти под своим аккаунтом чтобы оставлять комментарии