今天在使用okHttp发送一个请求时,由于需要查看返回的信息,便想用Toast显示该信息,没想到报错了:
究其原因,原来是因为okHttp发送请求时新开了一个子线程,而Toast消息不能在子线程中弹出,故有此报错。
问题原因
Android中的UI是线程不安全的,因此要更新UI必须在主线程中进行。
有两种更新UI的方法,一种是runOnUIThread,另一种是Handler().post(),顺便学习一下这两者的区别吧。
解决方案
- runOnUiThread(Runnable action)
//源码
/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
* 在UI线程中执行特定操作。如果当前线程是UI线程,则操作将马上执行。
* 反之则将操作发送到UI线程的事件队列等待执行。
* @param action the action to run on the UI thread
*/
@Override
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
在网上查阅资料后,发现如下的一段话:
runOnUiThread is basically suited to show a progress dialog or do some UI manipulations before an AsyncTask call. If you want to update the UI in the middle of a thread execution, then the best approach is to create a Handler which will update your UI, and let the thread continue running, for example, updating a text view periodically after a few sec, say timer functionality.
意思是说如果想在异步线程前执行某些UI操作(如更新progressBar进度),适合用runOnUiThread方法;
但如果想在线程中执行UI操作,还是推荐用Handler。
注意:runOnUiThread()是Activity中的方法,所以使用时应指明所在Activity,例如:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "UI action in UI Thread", Toast.LENGTH_LONG).show();
}
});
- 使用Thread+Handler处理
public static final int UPDATE_UI=1;
Handler handler=new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case UPDATE_UI:
//此处进行UI操作
...
}
}
});
new Thread(new Runnable(){
@Override
public void run(){
Message message=new Message();
message.what=UPDATE_UI;
handler.sendMessage(message);
}
});
或使用Handler(Looper.getMainLooper())
private void toastTest() {
new Thread(new Runnable() {
@Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "UI action in UI Thread", Toast.LENGTH_LONG).show();
}
});
}
}).start();
}