[Android] study notes of setContentView

Start an Activity

performLaunchActivity()

The ActivityThread.performLaunchActivity() method is the key method responsible for launching an Activity in the Android system.

When startActivity()a method is called to start an Activity, ActivityThreadthe object receives the request and calls performLaunchActivity() the method.

Inside the performLaunchActivity() method, a new one is first created ActivityRecord 对象to represent the Activity to be launched.

Next, activity.attach() the method will be called, which is used to associate the Activity object with the ActivityRecord and 初始化the corresponding properties.

In the activity.attach() method, an PhoneWindowobject is first created. PhoneWindow is the window associated with Activity and provides window management functions.

Then, methods are called mInstrumentation.callActivityOnCreate()to trigger the Activity's lifecycle callback methods onCreate().

mInstrumentation It is a tool class for Activity lifecycle scheduling and event dispatching. It can call various lifecycle callback methods such as onCreate(), onStart(), onResume(), etc.

callActivityOnCreate() method calls the Activity's onCreate() method in the main thread to perform some initialization operations.

onCreate() It is an important life cycle method, which is used to perform necessary initialization when the Activity is created, such as setting the layout, obtaining the passed data, and so on.

PhoneWindow

The PhoneWindow class is mainly responsible for the window management of the display interface in Android, and it will create the following types of windows

Activity:
When you start an Activity, the system creates an associated PhoneWindow object for the Activity. The PhoneWindow object is responsible for carrying the layout and interface display of the Activity.

Dialog(对话框):
The Dialog class is a window displayed in the form of a dialog box, and it also depends on PhoneWindow. When you create a dialog, the system creates an independent PhoneWindow object for it to host the layout and content of the dialog.

PopupWindow(弹出窗口):
PopupWindow is a window floating on top of other views, which also requires PhoneWindow to create and manage. When you create a PopupWindow instance, the system automatically creates a PhoneWindow object for it.

Toast(消息提示):
The creation of Toast does not directly depend on PhoneWindow, but when displaying Toast messages, a temporary window will be created through PhoneWindow for displaying content.

When the created Activity inherits the Activity, call setContentView

PhoneWindow.setContentView():
setContentView(layoutResID) The method is triggered when the method is called in the Activity PhoneWindow 的 setContentView() . Its main purpose is to create DecorView and get a content view.

installDecor():
The installDecor() method is a private method in PhoneWindow, which is responsible for creating and obtaining DecorView mContentParent(内容视图的父容器).

generateDecor(-1):
In the installDecor() method, generateDecor() the method is called to generate an DecorView object and stored in the mDecor member variable. This DecorView is the root view in PhoneWindow that hosts interface content.

generateLayout(mDecor):
ViewGroupThe generateLayout() method is an auxiliary method for generating the layout, returns an object as the parent container of the content view through the incoming DecorView , and stores it in mContentParentthe member variable.

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource):
In the generateLayout() method, onResourcesLoaded() the method of mDecor is called, which is used to handle related operations after resource loading is completed.

mLayoutInflater.inflate(layoutResID, mContentParent):
Finally, call the method in PhoneWindow mLayoutInflater.inflate(layoutResID, mContentParent) to fill the specified layout resource (such as R.layout.activity_main) into mContentParentand render the layout on the interface.

insert image description here

When the created Activity inherits AppCompatActivity, call setContentView

Compared with inheriting Activity, the process of inheriting AppCompatActivity will have some steps related to compatibility.

AppCompatDelegate.setContentView():
setContentView(layoutResID) The method that will be triggered when you call the method AppCompatDelegate in AppCompatActivity setContentView() . It is responsible for ensuring 正确的子布局(subDecor)被创建并设置为内容视图.

ensureSubDecor():
ensureSubDecor() method is invoked for 确保子布局 subDecor 被正确创建. It will call createSubDecor()method to generate subDecor object.

createSubDecor():
createSubDecor() The method is mainly responsible for 创建 subDecor 对象carrying the content of the interface 根视图. In this method, will be called ensureWindow()to ensure that the associated PhoneWindowis created correctly, and then mWindow.getDecorView()get the root view of PhoneWindow through .

复制内容视图:
In createSubDecor()the method, will 原始的内容视图(android.R.id.content)的子视图copy the content 新的容器视图(R.id.action_bar_activity_content)into one, and the original content view's id 设置为 NO_ID, will 新容器视图的 id 设置为 android.R.id.content.

设置 subDecor:
Finally, mWindow.setContentView(subDecor)set the subDecor to the PhoneWindow's via method 内容视图.

布局创建与解析:
In the process of creating a layout, LayoutInflaterthe specified layout resource will be parsed and 反射创建the corresponding View object will be passed. If the layout tag name contains the package name, the corresponding one will be created directly through reflection View 对象; otherwise, onCreateView() the View object will be created through the method. After the creation is completed, the creation and analysis of the subviews will be carried out, and finally the view structure of the entire layout will be obtained.

insert image description here

The role of LayoutInflate parameters

LayoutInflater is a class in Android, which is used to convert layout resource files into corresponding view objects. Its main function is to create the corresponding view hierarchy according to the specified layout resource file (XML file), and instantiate it as a View object.

With LayoutInflater, you can dynamically load and create layouts in code without using static XML layout files. This allows different views to be dynamically created as needed at runtime and added to the corresponding parent container.

The functions of several parameters of LayoutInflater are as follows:

layoutResID:
This is the ID of the layout resource file that needs to be loaded. By specifying the ID of the resource file, LayoutInflater can load the corresponding layout file according to the ID.

root:
This is the parent container that is required when loading the layout. When loading the layout, if you need to add the layout to a parent container, you can specify it as root. You can set root to null if you do not need to add the layout to the parent container.

attachToRoot:
This is a flag that indicates whether to add the loaded layout view to the root parent container. If set to true, the loaded layout view will be directly attached to the root parent container; if set to false, the loaded layout view will only be returned without being added to the root parent container.

example
// 方式一:将布局添加成功
View view = inflater.inflate(R.layout.inflate_layout, ll, true);
// 方式二:报错,一个View只能有一个父亲(The specified child already has a parent.)
View view = inflater.inflate(R.layout.inflate_layout, ll, true); // 已经addView
ll.addView(view);
// 方式三:布局成功,第三个参数为false
// 目的:想要 inflate_layout 的根节点的属性(宽高)有效,又不想让其处于某一个容器中
View view = inflater.inflate(R.layout.inflate_layout, ll, false);
ll.addView(view);
// 方式四:root = null,这个时候不管第三个参数是什么,显示效果一样
// inflate_layout 的根节点的属性(宽高)设置无效,只是包裹子View,
// 但是子View(Button)有效,因为Button是出于容器下的
View view = inflater.inflate(R.layout.inflate_layout, null, false);
ll.addView(view);
Remarks: View has no parent container =>>> the size parameter setting is invalid

Why requestWindowFeature() should be called before setContentView()

requestWindowFeature() A method actually calls PhoneWindow.requestFeature() a method. This method checks to see mContentParentExplicitlySet if a variable named is true, and throws an error if it is.

The purpose of calling requestWindowFeature() before the PhoneWindow.setContentView() method call is to ensure that the window feature is requested before setting the layout content. setContentView()Calling requestWindowFeature() after mContentParentExplicitlySet 变量会在 setContentView() 方法内部被设置为 truethis will raise an error if called first .

Therefore, the correct order is to call requestWindowFeature() to request window features first, and then call setContentView() to set the layout content. This avoids errors and enables the required window features correctly.

Why is it designed this way?

Window layout in Android is DecorView implemented by . DecorView is a root view that represents all the content of the active window, including the title bar, content area, and other decoration elements.

requestWindowFeature() The method is designed to be in 创建 DecorView 之前设置窗口的特征. This ensures that when the active window is created, how the window's appearance and behavior are drawn is determined according to the settings of the trait.

When the setContentView() method is called, the DecorView will be created and the content area will be added. Before doing this, the system needs to know which window characteristics to use to decide how to draw the DecorView. That's why you should call requestWindowFeature() before calling setContentView().

Through in requestWindowFeature() 中设置特征, we can control the appearance and function of the window, such as whether to display the title bar, progress bar, etc. This design approach allows us to load the layout before the activity 对窗口进行必要的配置.

Why requestWindowFeature(Window.FEATURE_NO_TITLE); setting is invalid?

requestWindowFeature(Window.FEATURE_NO_TITLE) The reason the setting doesn't work is because your activity inherits from AppCompatActivity, not directly from, Activity. In AppCompatActivity, the handling of title bar is different from that of traditional Activity.

In AppCompatActivity, supportRequestWindowFeature(Window.FEATURE_NO_TITLE) methods should be used to request that the title bar be hidden. This is because AppCompatActivity provides support for a compatibility feature that ensures that the title bar is hidden consistently across different versions of Android.

The supportRequestWindowFeature() method is a method of AppCompatActivity, which is used to set window features. You can request that the title bar be hidden in an activity by calling supportRequestWindowFeature(Window.FEATURE_NO_TITLE).

So, if your activity inherits from AppCompatActivity, and you want to hide the title bar, you should use supportRequestWindowFeature(Window.FEATURE_NO_TITLE) the method instead requestWindowFeature(Window.FEATURE_NO_TITLE). The former will ensure that hiding of the title bar is handled correctly.

Guess you like

Origin blog.csdn.net/qq_43358469/article/details/131889088