Android的动态文本更新 - ViewRootImpl $ CalledFromWrongThreadException

时间:2015-08-05 06:37:19

标签: java android error-handling

我是Android的初学者,所以如果这是一个愚蠢的问题,请善待。

我正在尝试动态更新四个TextView。每当我尝试更新它们时,程序都会崩溃。

我不明白解释“只有创建视图层次结构的原始线程才能触及其视图。”

这是我的班级:

Globals g = new Globals();

String l1 = "";
String l2 = "";
String l3 = "";
String l4 = "";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_game);
}

@Override
public void onStart() {
    super.onStart();
    //View view = getLayoutInflater().inflate(R.layout.activity_game, null);
    run ();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_game, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

private void nextLine (String s, int pauseTime, TextView first, TextView second, TextView third, TextView fourth)
{
    l4 = l3;
    l3 = l2;
    l2 = l1;
    l1 = s;

    first.setText (l1);
    second.setText (l2);
    third.setText (l3);
    fourth.setText(l4);

    try
    {
        Thread.sleep (pauseTime);
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }
}

@Override
public void onPause ()
{
    super.onPause ();
}

@Override
public void run () {
    Thread thread = new Thread() {
        @Override
        public void run() {
            TextView first = (TextView) findViewById(R.id.botLine);
            TextView second = (TextView) findViewById(R.id.secondLine);
            TextView third = (TextView) findViewById(R.id.thirdLine);
            TextView fourth = (TextView) findViewById(R.id.fourthLine);

            first.setTypeface(Typeface.MONOSPACE);
            second.setTypeface(Typeface.MONOSPACE);
            third.setTypeface(Typeface.MONOSPACE);
            fourth.setTypeface(Typeface.MONOSPACE);

            first.setTextSize((float) g.getTextSizeInt());
            second.setTextSize((float) g.getTextSizeInt());
            third.setTextSize((float) g.getTextSizeInt());
            fourth.setTextSize((float) g.getTextSizeInt());

            nextLine("1", 1000, first, second, third, fourth);
            nextLine("2", 1000, first, second, third, fourth);
        }
    };
    thread.start();
}

...这是我的LogCat:

08-05 02:33:34.129  14823-14854/com.mycompany.TestApp E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-190
    Process: com.mycompany.TestApp, PID: 14823
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357)
            at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:909)
            at android.view.ViewGroup.invalidateChild(ViewGroup.java:4690)
            at android.view.View.invalidateInternal(View.java:11801)
            at android.view.View.invalidate(View.java:11765)
            at android.view.View.invalidate(View.java:11749)
            at android.widget.TextView.checkForRelayout(TextView.java:6858)
            at android.widget.TextView.setText(TextView.java:4057)
            at android.widget.TextView.setText(TextView.java:3915)
            at android.widget.TextView.setText(TextView.java:3890)
            at com.mycompany.TestApp.Game.nextLine(Game.java:64)
            at com.mycompany.TestApp.Game.access$000(Game.java:13)
            at com.mycompany.TestApp.Game$1.run(Game.java:106)
08-05 02:33:34.266  14823-14839/com.mycompany.TestApp W/EGL_emulation﹕ eglSurfaceAttrib not implemented
08-05 02:33:34.266  14823-14839/com.mycompany.TestApp W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xb3f1ff20, error=EGL_SUCCESS

...和XML代码:

<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:id="@+id/botLine"
    android:layout_marginBottom="70dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:id="@+id/secondLine"
    android:layout_marginBottom="70dp"
        android:layout_above="@+id/botLine"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/thirdLine"
        android:layout_marginBottom="70dp"
        android:layout_above="@+id/secondLine"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/fourthLine"
        android:layout_marginBottom="70dp"
        android:layout_above="@+id/thirdLine"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>

2 个答案:

答案 0 :(得分:1)

程序正在崩溃,因为您正在尝试从非UI线程更新TextView上的文本。

用这个替换你的run()方法:

public void run () {
Handler handler = new Handler(Looper.getMainLooper);
handler.post(new Runnable(){
    @Override
    public void run(){
         TextView first = (TextView) findViewById(R.id.botLine);
        TextView second = (TextView) findViewById(R.id.secondLine);
        TextView third = (TextView) findViewById(R.id.thirdLine);
        TextView fourth = (TextView) findViewById(R.id.fourthLine);

        first.setTypeface(Typeface.MONOSPACE);
        second.setTypeface(Typeface.MONOSPACE);
        third.setTypeface(Typeface.MONOSPACE);
        fourth.setTypeface(Typeface.MONOSPACE);

        first.setTextSize((float) g.getTextSizeInt());
        second.setTextSize((float) g.getTextSizeInt());
        third.setTextSize((float) g.getTextSizeInt());
        fourth.setTextSize((float) g.getTextSizeInt());

        nextLine("1", 1000, first, second, third, fourth);
        nextLine("2", 1000, first, second, third, fourth);
  }

}); }

答案 1 :(得分:0)

您无法从其他线程更改UI,您应该使用处理主线程的方法,例如您可以尝试ASYNCtask在后台执行您想要的操作然后更改onPostExecute()中的文本视图
在这里你是它的链接:
http://developer.android.com/reference/android/os/AsyncTask.html

更新: AsyncTask的示例

class Name extends AsyncTask<Void, Void, Boolean>{
    //you can add variables here to be public in the class
    // also you can add a constructor to the class

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // here the code that you wanna do before starting the thread
        // you can delete this method if you want
    }
    @Override
    protected Boolean doInBackground(Void... parms) {
        // this is the method that will do the word away from the main thread
        // it must exist in the AsyncTask
        // this method will return boolean but you should check if it's null or not
    }
    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        // in this method you can deal with UI
    }
}