Android中Activity的View組成
原始碼基於API25
最簡單的Activity
這裡以繼承自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
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
<!--
This is an optimized layout for a screen, with the minimum set of features
enabled.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<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
體系
參考
end