安卓不允许子线程更新UI是因为UI访问是没有加锁的,多个线程访问UI不是线程安全的
检测机制:ViewRootImpl的checkThread()检测当前线程是否是UI线程,否则抛异常
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
ViewRootImpl 在Activity的onResume()时的创建过程:
源码中可以看到
ActivityThread的handleResumeActivity
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
if (r != null) {
...
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
...
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
...
} else {
...
}
}
- > Activity的makeVisible
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
注释:
WindowManager是外界访问窗口的入口;
WindowManager是一个接口,它的真正实现是WindowManagerImpl
WindowManagerImpl这种工作模式是典型的桥接模式,将所有的操作全部委托给WindowManagerGlobal来实现
- > WindowManagerGlobal的addView
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
...
}
}
- > ViewRootImpl
由源码可知,检测UI更新是否在主线程的操作是在Activity的onResume()方法中执行的
如果在子线程立刻访问UI,此时还没走到的的的onResume()方法,系统则不会抛出异常