2012-07-07 73 views
0

我正在尝试为Google TV制作一个遥控器。 我想要在设备成功连接时更改已连接的布局文本(TextView statusText)。但是当我尝试这样做时,我收到了一个异常: “07-07 22:42:20.870:E/AndroidRuntime(5750):android.view.ViewRootImpl $ CalledFromWrongThreadException:只有创建视图层次结构的原始线程可以触摸它。意见 “

感谢所有帮助/指针

这是我MainActivity.java和main.xml中:无法在Android回调中处理TextView

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

的main.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> 
+0

标有评论,我试图设置TextView与/这是我在哪里试图设置TEXTVIEW – MYR 2012-07-07 22:02:05

回答

2

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

+0

谢谢!正如你所看到的,我正在使用一个处理程序,我所做的只是移动代码,将TextView文本更改为我对该处理程序所做的文章。 – MYR 2012-07-08 14:34:28