1.引言
前幾天去面試有過這樣的問題喘沿。都知道在非ui線程中不能進行ui操作,但是為什么不能進行ui線程的操作竭贩。問的我不知所措蚜印。所以決定抽時間,看看博客 找找源碼留量,看看為什么
2.正題
2.1ViewManager
Paste_Image.png
2.2WindowManager
windowManager 是繼承于ViewManager窄赋。所以windowManager里面存在addView()方法。
Paste_Image.png
2.3 WindowManager實現(xiàn)類WindowManagerImpl
windowManager.addView() 實際調(diào)用的是WindowManagerGlobal.addView()
Paste_Image.png
2.4WindowManagerGlobal類
Paste_Image.png
addView方法的核心代碼
{
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
root = new ViewRootImpl(view.getContext(), display);//重要
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
可以看到ViewRootImpl 又調(diào)用了addView楼熄。查看ViewRootImpl的源代碼發(fā)現(xiàn)忆绰。
2.5ViewRootImpl 構(gòu)造方法
Paste_Image.png
根據(jù)mThread,進一步查找到
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
查到這步我們就可以知道了:setContentView是在主線程中進行的可岂,其ViewRootImpl指向主線程较木。 在子線程操作View结洼。Thread.currentThread()不再是UI線程挟阻。故而不想等,報錯木羹。