ActivityThread.handleLaunchActivity
Instrumentation.newActivity
Activity.attach
初始化 PhoneWindow 实例
Instrumentation.callActivityOnCreate
Activity.onCreate -> Activity.setContentView
PhoneWindow.setContentView -> PhoneWindow.installDecor
PhoneWindow.generatorDecor : 生成 DecorView
PhoneWindow.generatorLayout
// 根据不同的Style,生成对应的布局,content 对应为 mContentParent
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
LayoutInflater.inflate(layoutResID, mContentParent)
ActivityThread.handleResumeActivity
ActivityThread.performResumeActivity
Activity.performResume
WindowManagerImpl.addView
WindowManagerGlobal.addView : 内部会保存 mViews、mRoots
ArrayList<View> mViews = new ArrayList();
ArrayList<ViewRootImpl> mRoots = new ArrayList();
ArrayList<WindowManager.LayoutParams> mParams = new ArrayList();
创建 ViewRootImpl,并调用 ViewRootImpl.addView
ViewRootImpl.requestLayout,触发 onAttachToWindow 并创建 Surface
ViewRootImpl.performTraversals
performLayout、performMeasure、performDraw
DecorView 通过 assignParent 将自己的 Parent 设置为 ViewRootImpl
具体代码细节,请查看:https://www.jianshu.com/p/0a72779ba88b
面试题:为什么需要主线程更新UI,子线程不能更新UI?
首先,并非在子线程里面更新UI就一定有问题,如下所示的代码,则可以完美更新UI
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
init();
new Thread(new Runnable() {
@Override
public void run() {
tv_sport_mile.setText("测试界面更新");
}
}).start();
}
但是,如果我们让线程等待2秒后再更新UI,则会发生报错,代码如下所示:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
init();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tv_sport_mile.setText("测试界面更新");
}
}).start();
}
异常报错日志如下图所示:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original
thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7021)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1047)
为什么在 onActivityCreated 方法里面可以实现子线程更新 UI,但是线程等待两秒后就异常呢?
我们首先看 ViewRootImpl 源码中的 requestLayout 和 checkThread 方法:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}