在 Thread 上与用户交互导致我的应用程序崩溃
Interaction with user on Thread cause my app crash
如果 TextView.setText 在线程中,我的应用程序会崩溃:
注意:以下 class 在 MainActivity 内部。
private class StreamThread extends Thread {
public StreamThread() {
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
//THIS IS IMPORTANT, READ THIS PLEASE
//I tested many times my app to find the problem, and I found, my app crashes when TextView.setText() is executed
//Here starts the problem
((TextView) findViewById(R.id.textView)).setText(message);
} catch (IOException e) {
break;
}
}
}
线程被设计为通过分离允许另一个代码同时执行来执行代码。
不幸的是线程与 UI 不兼容,但我有一个解决方案。
runOnUiThread(new Runnable() {
@Override
public void run () {
//Some stuff that needs to interact with the user (UI).
}
}
您必须在 ui 线程中更新视觉组件。为了您的目的,您应该使用在 ui 线程中运行的 AsyncTask、Service 或 Runnable。
例如,您在以下代码中使用 AsyncTask:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textview = (TextView) findViewById(R.id.textView);
new StreamAsyncTask(textview).execute();
}
private class StreamAsyncTask extends AsyncTask<Void, String, Void> {
private TextView textview;
public StreamAsyncTask(TextView textview) {
this.textview = textview;
}
@Override
protected Void doInBackground(Void... voids) {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
publishProgress(message);
} catch (IOException e) {
break;
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
textview.setText(values[0]);
}
}
}
或者你可以使用Activity的方法runOnUiThread:
runOnUiThread(new Runnable() {
@Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
最后一种方式更容易理解,但第一种方式更灵活。
了解 AsyncTasks:http://developer.android.com/reference/android/os/AsyncTask.html
这应该可以解决问题:
private class StreamThread extends Thread {
public StreamThread() {}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
@Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
} catch (IOException e) {
break;
}
}
}
}
太好了,怎么了?
Android 的 UI 是单线程的。
这意味着您不能从 ui 线程之外的另一个线程更改 ui。
您可以使用 runOnUiThread-Method or using a Handler.
post 更改 ui 线程
如果 TextView.setText 在线程中,我的应用程序会崩溃:
注意:以下 class 在 MainActivity 内部。
private class StreamThread extends Thread {
public StreamThread() {
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
//THIS IS IMPORTANT, READ THIS PLEASE
//I tested many times my app to find the problem, and I found, my app crashes when TextView.setText() is executed
//Here starts the problem
((TextView) findViewById(R.id.textView)).setText(message);
} catch (IOException e) {
break;
}
}
}
线程被设计为通过分离允许另一个代码同时执行来执行代码。 不幸的是线程与 UI 不兼容,但我有一个解决方案。
runOnUiThread(new Runnable() {
@Override
public void run () {
//Some stuff that needs to interact with the user (UI).
}
}
您必须在 ui 线程中更新视觉组件。为了您的目的,您应该使用在 ui 线程中运行的 AsyncTask、Service 或 Runnable。
例如,您在以下代码中使用 AsyncTask:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textview = (TextView) findViewById(R.id.textView);
new StreamAsyncTask(textview).execute();
}
private class StreamAsyncTask extends AsyncTask<Void, String, Void> {
private TextView textview;
public StreamAsyncTask(TextView textview) {
this.textview = textview;
}
@Override
protected Void doInBackground(Void... voids) {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
publishProgress(message);
} catch (IOException e) {
break;
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
textview.setText(values[0]);
}
}
}
或者你可以使用Activity的方法runOnUiThread:
runOnUiThread(new Runnable() {
@Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
最后一种方式更容易理解,但第一种方式更灵活。 了解 AsyncTasks:http://developer.android.com/reference/android/os/AsyncTask.html
这应该可以解决问题:
private class StreamThread extends Thread {
public StreamThread() {}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
@Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
} catch (IOException e) {
break;
}
}
}
}
太好了,怎么了? Android 的 UI 是单线程的。 这意味着您不能从 ui 线程之外的另一个线程更改 ui。 您可以使用 runOnUiThread-Method or using a Handler.
post 更改 ui 线程