1.什么是UI线程?UI线程等于主线程吗?
1.1 Activity#runOnUiThread
如果当前的应用组件是Activity,我们经常在子线程里面刷新ui的时候会这样操作
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
//Activity启动的时候会创建,这些是在主线程
final void attach(Context context){
mUiThread = Thread.currentThread();
}
从上面可以看出,==mUiThread是创建Activity的时候attach所在的线程==,所以ui线程就是主线程。
1.2 View.post
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
//有可能ViewRootImpl还没有创建好
getRunQueue().post(action);
return true;
}
/**
* A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
* handler can be used to pump events in the UI events queue.
*/
final Handler mHandler;
这里的AttachInfo 是在ViewRootImpl创建的时候创建的,所以是在主线程, mHandler是在主线程中创建的Handler,所以刷新ui也会切换到主线程中去。==对于View来说,它的UI线程就是ViewRootImpl所在的线程==,如果不在这个线程去刷新ui就会抛异常
1.3 UI线程是怎么启动的
就是ActivityThread的main()的启动,涉及到消息循环。
-
说说UI线程是什么?
-
UI消息循环是怎么创建的?
可以简单说说应用进程是怎么启动的
-
UI线程和UI体系之间的关系
谈谈ViewRootImpl
一定切记不是说不能在子线程中去刷新ui,如下例子:
new Thread(){
public void run(){
Looper.prepare();
getWindowManager.addView(view, params);
Looper.loop();
}
}.start()
这个例子中,我们就是在子线程中去添加View到DecorView,这时候刷新ui就应该在子线程中了,在主线程中刷新ui反而会抛异常。
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
==我们一定要劳记这个异常的本质。本质就是,刷新当前ui的线程必须和添加当前ui的线程保持一致,也就是说,如果你的ui是在主线程中添加的(例如常规的Activity中的ui),那么你就在主线程中去刷新,反之,你的ui是在子线程中添加的(例如上面的例子),那么你就需要在子线程中去刷新。==系列线程