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);
			}
		});
	}
}

Напишіть перше повідомлення!

Ви повинні увійти під своїм аккаунтом щоб залишати коментарі