思考:
- 1.什么是UI线程?
- 2.UI线程是主线程吗?
什么是UI线程?
先必须了解下面2个问题
1.顾名思义 UI线程 就是刷新UI 所在线程
2.UI是单线程刷新
UI线程就一定是主线程吗?
1.对Activity 来说 UI线程就是其主线程
2.对View来说 UI线程就是创建ViewRootImpl所在的线程
可以通过 WindowManager 内部会创建ViewRootImpl对象
好了,进入主题。我们来慢慢揭开面纱。
我们可以分别从几个方面切入
-
1.Activity 的runOnUiThread 方法
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
我们可能都有使用过 runOnUiThread 现在来看看的源码实现。
public final void runOnUiThread(Runnable action) {
//判断当前线程 是否是UI 线程
if (Thread.currentThread() != mUiThread) {
//切到UI 线程
mHandler.post(action);
} else {
action.run();
}
}
可以从上面的源码 看到
不是UI线程 就用Handler切到Handler所在的线程中,如果是UI线程直接就调用run方法。
- 1.那么Handler 在那里创建呢?没错 它就是Activity 的成员变量(final Handler mHandler = new Handler()),对应Activity 所在的线程,也就是Activity 所在线程的looper。
- 2.在来看Activity mUiThread
final void attach(){
//调用attach所在的线程
mUiThread = Thread.currentThread();
}
Activity的创建:
1.Activity创建:mInstrumentation.newActivity
2.创建Context :ContextImpl appContextcreateBaseContextForActivity(r)
- attach
- onCreate
结论:
以上都是在应用的主线程中创建,那么可以确认 对于Activity来说 UI线程就是 主线程。
-
2.View的post方法
view.post(new Runnable() {
@Override
public void run() {
}
});
我们经常用这个方法干的事情就是,要么在onCreate中获取View宽高的值。要么就是在子线程中做一些耗时操作 ,然后post切到对应View所在的线程 来绘制UI操作。那么这个对应的线程就是UI线程了。
那么这个UI线程就一定是主线程吗?
接来继续来看。它的源码View:post
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
getRunQueue().post(action);
return true;
}
mAttachInfo 在dispatchAttachedToWindow 中被赋值 ,也就是在ViewRootImpl创建的时候,所以是创建ViewRootImpl所在的线程。
attachInfo 上面时候为null 呢?在ViewRootImpl 还没来得及创建的时候,ViewRootImpl 创建是在 “onResume" 之后。所以在 Activity 的 onCreate 去View.post 那么AttachInfo 是为null 。
当 AttachInfo == null 那么会调用 getRunQueue().post(action) 。
最终这个Runnable 被 缓存到 HandlerActionQueue 中。
直到ViewRootImpl 的 performTraversals 中 调用dispatchAttachedToWindow(mAttachInfo, 0);, 那么才会去处理 RunQueue() 中的Runnable。
来张图 便于理解这个流程
结论:
对View 来说,它的UI线程 就是 ViewRootImpl创建所在的线程 。
View的checkThread
我们有时候去子线程操作UI的时候(如:requestLayout),会很经常见到下面的 报错日志:
Only the original thread that created a view hierarchy can touch its views
ViewRootImpl 的checkThread :
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
为什么会报这个错误呢?
翻译一下:只有创建视图层次结构的原始线程才能接触到它的视图。
也就是操作UI的线程要和ViewRootImpl创建的线程是同一个线程才行,并不是只有主线程才能更新UI啊。
ViewRootImpl创建的线程?那么 ViewRootImpl 在哪里被创建的呢?
从上图可以看到ViewRootImpl创建最开始是从 ActivityThread 的HandleResumeActivity中开始 一直 ViewRootImpl 创建,也就是说ViewRootImpl 对应的UI线程和 ActivityThread 在同一个线程 也就是主线程。
结论
Activity的DecorView 对应的ViewRootImpl是在主线程中创建的
需要注意的是 哪个线程创建了 ViewRootImpl 那么UI线程就是哪个线程。
对于Android 系统 而言, ViewRootImpl创建 默认是在主线程中创建的 所对应的UI线程就是主线程。
好了 通过上面的讲解,上面的问题相信你可以自己回答啦~