0

我正在尝试为 Google TV 制作遥控器。我想在设备成功连接后更改布局中的文本(TextView statusText)。但是当我尝试这样做时出现异常:“07-07 22:42:20.870: E/AndroidRuntime(5750):android.view.ViewRootImpl$CalledFromWrongThreadException: 只有创建视图层次结构的原始线程才能触摸其视图."

感谢任何帮助/指针

这是我的 MainActivity.java 和 main.xml:

MainActivity.java:

package uk.co.mypack.gtvremote;

//imports removed for paste

public class MainActivity extends Activity implements ClientListener{

    private AnymoteSender anymoteSender;
    private TextView statusText;
    protected AnymoteClientService mAnymoteClientService;
    private static String statusPrefix = "Status: ";
    private Context mContext;
    private ProgressBar progressBar;

    private Handler handler;
    private TouchHandler touchPadHandler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progressBar = (ProgressBar) findViewById(R.id.a_progressbar);
        progressBar.setVisibility(View.VISIBLE);

        mContext = this;



        ImageButton upArrowButton = (ImageButton) findViewById(R.id.upArrow);
        ImageButton leftArrowButton = (ImageButton) findViewById(R.id.leftArrow);
        ImageButton centreButton = (ImageButton) findViewById(R.id.centreButton);
        ImageButton rightArrowButton = (ImageButton) findViewById(R.id.rightArrow);
        ImageButton downArrowButton = (ImageButton) findViewById(R.id.downArrow);

        upArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                sendKeyEvent(KeyEvent.KEYCODE_DPAD_UP);
            }
        });

        leftArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                sendKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
            }
        });

        centreButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                sendKeyEvent(KeyEvent.KEYCODE_DPAD_CENTER);
            }
        });

        rightArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                sendKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
            }
        });

        downArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                sendKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN);
            }
        });


        handler = new Handler();

        // Bind to the AnymoteClientService
        Intent intent = new Intent(mContext, AnymoteClientService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        statusText = (TextView) findViewById(R.id.statusText);


    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {
        /*
         * ServiceConnection listener methods.
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            mAnymoteClientService = ((AnymoteClientService.AnymoteClientServiceBinder) service)
                    .getService();
            mAnymoteClientService.attachClientListener(MainActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mAnymoteClientService.detachClientListener(MainActivity.this);
            mAnymoteClientService = null;   
        }

    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onConnected(AnymoteSender anymoteSender) {
        if (anymoteSender != null) {
            // Send events to Google TV using anymoteSender.
            // save handle to the anymoteSender instance.
            this.anymoteSender = anymoteSender;

            //THIS IS WHERE I AM TRYING TO SET THE TEXTVIEW

            TextView localStatusText = (TextView) findViewById(R.id.statusText);
            localStatusText.setText(statusPrefix + "Connected to GoogleTV");

            //ABOVE IS WHERE I AM TRYING TO SET THE TEXTVIEW

            // Attach touch handler to the touchpad view
            touchPadHandler = new TouchHandler(
                    findViewById(R.id.touchPad), Mode.POINTER_MULTITOUCH, anymoteSender);

        } else {
            statusText.setText(statusPrefix + "Connection attempt failed, cant find send handler");
            //attempt to connect again?
            //attemptToConnect();
        }

        // Hide the progressBar once connection to Google TV is established.
        handler.post(new Runnable() {
            public void run() {
                progressBar.setVisibility(View.INVISIBLE);
            }
        });
    }

    @Override
    public void onDisconnected() {
        // show message to tell the user about disconnection.
        statusText.setText(statusPrefix + "Disconnected");
        // Try to connect again if needed. This may be need to be done via button
        attemptToConnect();
        this.anymoteSender = null;

    }

    @Override
    public void onConnectionError() {
        // show message to tell the user about disconnection.
        statusText.setText(statusPrefix + "Connection error encountered");
        // Try to connect again if needed.
        attemptToConnect();
        this.anymoteSender = null;

    }

    @Override
    protected void onDestroy() {
        if (mAnymoteClientService != null) {
            mAnymoteClientService.detachClientListener(this);
        }
        unbindService(mConnection);
        super.onDestroy();
    }

    public void attemptToConnect()
    {
        //stub to invoke connection attempt
    }

    private void sendKeyEvent(final int keyEvent) {
        // create new Thread to avoid network operations on UI Thread
        if (anymoteSender == null) {
            Toast.makeText(MainActivity.this, "Waiting for connection",
                    Toast.LENGTH_LONG).show();
            return;
        }
        anymoteSender.sendKeyPress(keyEvent);
    }
}

主要.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/control_message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="@dimen/padding_medium"
        android:text="@string/control_msg"
        android:textSize="90dp"
        tools:context=".MainActivity" />

    <LinearLayout
        android:id="@+id/middlePanel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/statusText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Status: Disconnected - startup"
            android:textSize="20dp" />

        <ImageView
            android:id="@+id/touchPad"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@drawable/greysquare" 
            />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <ImageButton
                android:id="@+id/upArrow"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:background="@drawable/blackuparrow" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:orientation="horizontal" >

                <ImageButton
                    android:id="@+id/leftArrow"
                    android:layout_width="150dp"
                    android:layout_height="150dp"
                    android:background="@drawable/blackleftarrow" />

                <ImageButton
                    android:id="@+id/centreButton"
                    android:layout_width="150dp"
                    android:layout_height="150dp"
                    android:background="@drawable/emptycircle"
                    android:paddingBottom="10dp"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="10dp" />

                <ImageButton
                    android:id="@+id/rightArrow"
                    android:layout_width="150dp"
                    android:layout_height="150dp"
                    android:background="@drawable/blackrightarrow" />
            </LinearLayout>

            <ImageButton
                android:id="@+id/downArrow"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:background="@drawable/blackdownarrow" />
        </LinearLayout>
    </LinearLayout>
<ProgressBar
        android:id="@+id/a_progressbar"
        style="@android:style/Widget.ProgressBar.Large"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
</LinearLayout>
4

1 回答 1

2

onConnected() 回调不在主 UI 线程上调用,而是在服务使用的单独线程上调用。所以它无法访问在主 UI 线程中创建的 TextView。您应该做的是在主 UI 线程中创建一个处理程序,然后使用该处理程序发布一个可对 TextView 进行更改的可运行文件。您可以在 Android 开发者网站上阅读更多关于处理程序的信息。

于 2012-07-08T07:10:33.610 回答