[英]Dynamic Text Update for Android - ViewRootImpl$CalledFromWrongThreadException
I'm a beginner with Android, so please be kind if this is a stupid question. 我是Android的初学者,所以如果这是一个愚蠢的问题,请多多关照。
I'm trying to dynamically update four TextViews. 我正在尝试动态更新四个TextView。 Whenever I try to update them, the program crashes. 每当我尝试更新它们时,程序就会崩溃。
I don't understand the explanation "Only the original thread that created a view hierarchy can touch its views." 我不理解“只有创建视图层次结构的原始线程才能触摸其视图”的解释。
Here is my class: 这是我的课:
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();
}
...and this is my LogCat: ...这是我的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
...and the XML code: ...以及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>
Program is getting crashed because you are trying to update the text on TextView from a non UI Thread. 程序崩溃,因为您试图从非UI线程更新TextView上的文本。
replace your run() method with this: 用以下代码替换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);
}
}); }); } }
You can't change the UI from another thread, you should use a method that deals with the main thread, for example you can try ASYNCtask to do what you want in the background then change the textviews in onPostExecute() 您不能从另一个线程更改UI,您应该使用处理主线程的方法,例如,您可以尝试ASYNCtask在后台执行您想要的操作,然后在onPostExecute()中更改文本视图
here you are a link to it: 这是您的链接:
http://developer.android.com/reference/android/os/AsyncTask.html http://developer.android.com/reference/android/os/AsyncTask.html
Update: example for AsyncTask 更新: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
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.