简书博客文章迁移https://www.jianshu.com/u/43a04ef9d4c6
源码基于API25
这里以继承自Activity为准,不是AppCompatActivity
,AppCompatActivity
是有一点不同的。
public class Main2Activity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
}
1.面带微笑
2.很显然,这个Activity里面可以由我们自定义的是
setContentView(R.layout.activity_main2);
3.查看setContentView()
源码
public void setContentView(@LayoutRes int layoutResID) {
//这里真正用的是getWindow()的setContentView()方法
getWindow().setContentView(layoutResID);
//初始化DecorView的ActionBar的,这里先不管
initWindowDecorActionBar();
}
4.getWindow()
返回的是Window
对象
5.mWindow
出处,在Activity
中搜索mWindow =
,最终发现它被初始化在attach()
中,attach()
部分源代码如下
可以看到mWindow
其实是PhoneView
对象
6.所以第3步getWindow().setContentView(layoutResID)
其实调用的是PhoneView类中的setContentView(layoutResID)
方法,PhoneView
在Android Studio中是报红色的,说明它应该是 用了@hide
注解,我们直接去SDK目录找PhoneView
类,位置在SDK\sources\android-25\com\android\internal\policy
下
7.PhoneView中的.setContentView(layoutResID)
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();//关键在这里
}
...//部分省略
}
8.installDecor();
...
ViewGroup mContentParent;
...
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);//关键在这里(A)
//省略部分源码
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);//(标记为B处)
//省略部分源码
...
}
}
9.先看(A)处generateDecor();
protected DecorView generateDecor(int featureId) {
//省略部分
return new DecorView(context, featureId, this, getAttributes());
}
可以看到返回的是DecorView,然后8中的B处调用了
mContentParent = generateLayout(mDecor);
10.接着看下generateLayout()
protected ViewGroup generateLayout(DecorView decor) {
......省略部分源码
//布局
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
//1.根据features获取不同的布局
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
}
.....
else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
//2.这个features就是我们通常在Activity中取消ActionBar的对应features
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else {
// Embedded, so no decoration is needed.
//3.加载默认的layoutResource
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
......省略部分源码,这里只贴出俩个features 的if
mDecor.startChanging();
//4.DecorView加载布局layoutResource
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
......省略部分源码
return contentParent;
重点看1,2,3,4处注释,2处就是我们通常取消ActionBar的features,3处加载了默认的布局文件,这个文件在framework层,路径是SDK\platforms\android-25\data\res\layout\screen_title.xml
,4处是DecorView加载了布局layoutResource
,
可以看到返回值是ViewGroup
类型的然后给了8处的B处的mContentParent
的(在installDecor()
它加载进了PhoneView
中)
11.screen_title.xml
布局文件,其中ViewStub
用来显示ActionBar
,第一个FrameLayout
中的TextView
用来显示title,第二个FrameLayout
用来显示content
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<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:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
LinearLayout>
12.总结一下,Activity
中初始化了PhoneView
,PhoneView
中初始化了DecorView
,DecorView
中选择布局or上面的默认布局,这样就形成了下图的Activity
体系
图片引用自http://liuwangshu.cn/application/view/6-activity-constitute.html
<<安卓开发艺术探索>>
源码解析Activity的构成
感谢各路大牛
end