android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
大概意思就是谁创建的view谁更改,别人不能碰。
为什么系统不能让子线程更新ui呢:
我感觉主要是UI控件不是线程安全的,多线程并发访问可能会导致ui控件处于不可预期的状态。 那为什么不对UI控件的访问加上 上锁机制 呢:
1.主要是加个锁后会使UI控件变得复杂而低效
2.上锁后会阻塞某些进程的执行,这对手机系统是不可接受的,所以采取简单高效的方法就是单线程模型来处理UI控件,通过 Handler切换一下访问的线程的就好 。
handler机制主要由四部分构成:
message消息对象 messagequeue消息队列 looper轮询器 handler处理消息 或者发送消息给另一个messagequeue 。
工作机制就是:handler中的messagequeue中的enqueueMessage插入一条信息到messagequeue中,然后looper不断轮询Messagequeue的next()方法,如果发现message调用handeler的dispatchMessge,idispatchMessage处理消息,接着调用handlermessage()。
messagequeue消息队列内部是链表结构,先进先出,有入队,出队方法。
looper轮询器主要作用是一直轮询messagequeue,发现message就交给handler处理 ,没有消息就一直处于阻塞状态。在主线程中系统自动提供looper 。而在子线程中创建handler一定要写looper.prepare()否则会报"Can't create handler inside thread that has not called Looper.prepare()"); ,,因为线程中使默认没有looper的,主线程除外。looper里面有一个Threadlocal,主要是帮助handler获得当前线程的looper。
looper.quit() 直接退出looper
looper.quitSafely() 建立一个标记,只有当目前已有消息处理完毕之后才会执行退出操作
Handler是一个消息辅助类,主要负责向消息池发送各种消息事件Handler.sendMessage()
和处理相应的消息事件Handler.handleMessage()
。
HandlerThread
是 Android API 提供的一个便捷的类,使用它可以让我们快速地创建一个带有 Looper
的线程,有了 Looper
这个线程,我们又可以生成 Handler
,本质上也就是一个建立了内部 Looper
的普通 Thread
。
他继承自thread ,所以在run()中的逻辑都是在子线程中运行的。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
源码里有两个重要的方法run()和getLooper():
run()中可以看到是很简单的创建Looper以及让Looper工作的逻辑。
run()里面当mLooper创建完成后有个notifyAll(),getLooper()中有个wait(),这有什么用呢?因为的mLooper在一个线程中执行创建,而我们的handler是在UI线程中调用getLooper()初始化的。
也就是说,我们必须等到mLooper创建完成,才能正确的返回。getLooper();wait(),notify()就是为了解决这两个线程的同步问题。