上篇文章:子线程更新主线程的View抛出异常全过程,ViewRootImpl的checkThread方法中,通过mThread来判断,要更新View的线程和创建View的线程,是不是同一个,如果不是就抛出异常。
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
那么这个mThread是什么时候被赋值的了?
ViewRootImpl的mThread什么时候赋的值?
在ViewRootImpl对象生成的时候,也就是ViewRootImpl的构造函数里面赋的值。
/frameworks/base/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
......
mThread = Thread.currentThread();
......
}
ViewRootImpl对象什么时候生成的?
//Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
//getWindowManager返回了mWindowManager
public WindowManager getWindowManager() {
return mWindowManager;
}
private WindowManager mWindowManager;
ViewManager是一个接口,WindowManager也是一个接口,WindowManager继承自ViewManager。如下:
/frameworks/base/core/java/android/view/ViewManager.java
/frameworks/base/core/java/android/view/WindowManager.java
public interface ViewManager//定义对View的增删改
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
public interface WindowManager extends ViewManager {
//可见WindowManager也提供对View的增删改的接口方法
......
}
WindowManager的具体实现类是WindowManagerImpl
,我们看看WindowManagerImpl#addView()方法。
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());
}
//mGlobal 是WindowManagerGlobal类的对象
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
......
}
接着看WindowManagerGlobal#addView()方法。
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
......
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
//创建ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
//设置View的布局属性
view.setLayoutParams(wparams);
//将相关信息保存到对应集合
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView, userId);//调用ViewRootImpl对象的setView方法(这里也是View绘制的根源)
} catch (RuntimeException e) {
...
}
}
}
在WindowManagerGlobal#addView()方法里,我们看到了ViewRootImpl对象的初始化。
总结:
WindowManagerGlobal
的addView()方法里面,生成了ViewRootImpl对象。
在子线程中更新view的问题
Window和WindowManager和ViewRootImpl
看到这里,继续追问:ViewRootImpl的初始化确定是在主线程吗?这个问题比较复杂,后面的文章,接着分析。
其他疑问
-
WindowManager与ViewRootImpl是什么关系?
WindowManagerGlobal有存储ViewRootImpl的集合,mRoots。
Window和WindowManager和ViewRootImpl -
mRoots是干啥的?
存储所有的ViewRootImpl。 -
Global为什么要保存ViewRootImpl?
后面会需要查询。 -
一个 Activity 有多少个 ViewRootImpl?
ViewRootImpl 是实际管理 Window 中所有 View 的类,每个 Activity 中 ViewRootImpl 数量取决于调用mWindowManager.addView() 的次数。
Framework篇 - 一文搞懂 Activity、View、Window、ViewRootImpl