一直对F码抱有一种敬畏之心,所以能不看就不看☺️。虽然看了很多关于Activity创建流程的技术文章,但也仅仅是休闲式的,只看不动手,当时感觉看的很明白,没过几天就又还给作者了,下次遇见此类问题,还是一脸懵逼。痛定思痛,决定自己看一下F码,再做个笔记,加深印象,也便于回顾。
大家都听说过Activity,Window,PhoneWindow,WindowManager,WindowManagerImpl,WindowManagerGlobal,WindowManagerServer,ViewRoot,ViewRootImpl等这些class吧,如果你和我一样对它们的关系一知半解,那么这个笔记很适合你。最好打开AS,跟着源码走一走
表演开始,这次不要🤮,会不会又跑路???😱
首先在ActivityThread的performLaunchActivity()方法通过反射创建Activity,activity调用attach()方法创建PhoneWindow;activity执行onCreate生命周期,setContentView(int)经过层层调用执行PhoneWindow的setContentView(View)方法,然后创建根布局DecorView,DecorView包含一个contentParent,我们setContentView就是把自己的页面添加到contentParent里面,现在页面已经建成,但还没有显示,接下来看ActivityThread的handleResumeActivity()方法,activity调用makeVisible()方法,mDecor.setVisibility(View.VISIBLE)显示
先说一下Window
有View的地方就有Window
Window分三大类,本文所讲的Window是应用程序Window
-
系统Window
例如Toast、输入法、低电量提示所对应的window -
应用程序Window
例如Activity所对应的window。每个Activity都有一个window,通过getWindow()获取,这里的返回的Window实际上PhoneWindow,Window是一个抽象类,具体实现类就是PhoneWindow -
子Window
例如PopWindow
在WindowManager里面可以看到又对Window的种类进行了细化,细化后的每种类型的Window都对应一个int类型的常量值,这个值越大,在Window层叠的时候就越靠上
Activity和Window的创建
ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//通过反射创建一个Activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
//调用attach(...),创建Window
activity.attach(...);
...
//调用callActivityOnCreate(...),Activity执行onCreate()
mInstrumentation.callActivityOnCreate(...);
...
return activity;
}
Activity.java
final void attach(...) {
...
//创建Window
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
}
页面显示
Activity.java
调用父类AppCompatActivity的setContentView方法
setContentView(R.layout.activity_main);
AppCompatActivity.java
AppCompatDelegate是一个接口,getDelegate()返回AppCompatDelegate的实现类AppCompatDelegateImpl,所以此处又调用AppCompatDelegateImpl的setContentView(int)方法
public void setContentView(@LayoutRes int layoutResID) {
this.getDelegate().setContentView(layoutResID);
}
@NonNull
public AppCompatDelegate getDelegate() {
if (this.mDelegate == null) {
this.mDelegate = AppCompatDelegate.create(this, this);
}
return this.mDelegate;
}
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
return new AppCompatDelegateImpl(activity, activity.getWindow(), callback);
}
AppCompatDelegateImpl.java
public void setContentView(int resId) {
this.ensureSubDecor(); //重要方法,安装DecorView
ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(16908290);
contentParent.removeAllViews();
LayoutInflater.from(this.mContext).inflate(resId, contentParent);
this.mOriginalWindowCallback.onContentChanged();
}
private void ensureSubDecor() {
if (!this.mSubDecorInstalled) {
this.mSubDecor = this.createSubDecor();
...
}
...
}
private ViewGroup createSubDecor() {
...
//mWindow是PhoneWindow
this.mWindow.getDecorView();
...
}
PhoneWindow.java
生成跟布局DecorView,DecorView继承FrameLayout,包括标题栏和内容部分(mContentParent),我们setContentView就是把view添加到mContentParent
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
...
}
if (mContentParent == null) {
//内容布局,Activity里面的setContentView就放到mContentParent里面
mContentParent = generateLayout(mDecor);
}
...
//把我们的布局添加到Content里面
mContentParent.addView(view, params);
...
}
protected DecorView generateDecor(int featureId) {
...
return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
...
//findViewById调用DecorView的findViewById,contentParent是DecorView的id为com.android.internal.R.id.content的子view
//Window的常量 public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
ActivityThread.java
回到ActivityThread
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {
...
//显示View
r.activity.makeVisible();
...
}
Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
//显示DecorView
mDecor.setVisibility(View.VISIBLE);
}
到此页面已经显示了,那么ViewManager怎么让DecorView显示在页面上的?下篇再进行分析...
第一次写技术文章,错误之处请包涵并指正
Thanks
End
网友评论