我们都知道,要在非UI线程更新UI需要使用到Handler或者AsyncTask(内部也是Handler实现),那么为什么就不能直接在子线程中更新UI,而要在UI线程中更新。这就扯到一个单线程和多线程问题,要知道UI线程中只有一个MainThread主线程,也就是单线程,而非UI线程的话就可能有多线程,关于一个线程安全问题。在多线程情况下如果去更新UI,所有线程同时在对一个UI进行访问,当前UI的状态就会无法获取到,导致线程安全问题,可以使用synchronized锁定当前线程,防止其他线程访问。这里也看到其他人的一些说法,就是跟显卡芯片有关,想想还是有点道理。所有的并发显示UI都是要排队的,只是给你的假象是在同时更新,如果芯片很差,就会出现绘制延迟和混乱,如果显卡芯片性能很高很高,在子线程更新UI也没什么问题,而目前在Google 新推出的Sky语言号称能达到120fps ,并且不会阻塞UI。要知道现在的Android手机很多连60fps都达不到。
另外当所有更新UI操作放到主线程时,如果存在一些比较耗时的工作比如访问网络或者数据库查询,都会堵塞UI线程,导致事件停止分发,也就是耗时操作要放在子线程。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。所以Android的单线程模型有两条原则
①不要阻塞UI线程,耗时操作放在子线程
②不要再UI线程之外访问UI组件
2.UI中子线程更新UI的3种方法
runOnUiThread(Runnable runnable)
/**
* 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.
*@param action the action to run on the UI thread
*/publicfinalvoidrunOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
/**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @see #postDelayed
* @see #removeCallbacks
*/publicbooleanpost(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
returntrue;
}
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/publicfinalbooleanpost(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
publicfinalbooleansendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
继续点击进去
publicbooleansendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
returnfalse;
}
return enqueueMessage(queue, msg, uptimeMillis);
}