This document describes how to add a view or viewgroup object to an application window.
The window mentioned below can refer to the interface we can see, including an activity Presentation Interface (we can understand it as an application window), a dialog, a toast, A menu.
First, we will give a brief introduction to the functions of related classes:
Window classIn/frameworks/base/CORE/Java/Android/View/window. Java
Note: This class is an abstract class that provides a set of common APIs for drawing windows. It can be understood as a carrier, and various views are displayed on this carrier.
The source file (Part) is as follows:
Public abstract class window {//... // specify the style type of the activity window public static final int feature_no_title = 1; public static final int feature_indeterminate_progress = 5; // set the layout file public abstract void setcontentview (INT layoutresid ); public abstract void setcontentview (view); // request public Boolean requestfeature (INT featureid) {final int flag = 1 <featureid; mfeatures | = flag; mlocalfe Atures | = mcontainer! = NULL? (Flag &~ Mcontainer. mfeatures): flag; Return (mfeatures & flag )! = 0 ;}//...}
Phonewindow classIn/frameworks/policies/base/phone/COM/Android/Internal/policy/impl/phonewindow. Java
Note: This class inherits from the window class, which is the specific implementation of the window class. That is, we can use this class to draw a window. In addition, this class contains a decorview object, which is the root view of all application windows (activity interfaces. In short, the phonewindow class encapsulates a framelayout class, namely, the decorview object, as the Root View of the application window, and provides a set of common window operation interfaces.
The source file (Part) is as follows:
Public class phonewindow extends window implements menubuilder. callback {//... // This is the top-level view of the window, containing the window decor. private decorview mdecor; // This object is the root view of all application windows and a subclass of framelayout. // This object is the parent view of the activity layout file, in general, it is a framelayout viewgroup // and a subview of the decorview object. // This is the view in which the window contents are placed. it is either // mdecor itself, or a child of MD EcoR where the contents go. Private viewgroup mcontentparent; // set the title @ override public void settitle (charsequence title) {If (mtitleview! = NULL) {mtitleview. settext (title) ;}mtitle = title ;}// set the background image @ override public final void setbackgrounddrawable (drawable) {If (drawable! = Mbackgrounddrawable | mbackgroundresource! = 0) {mbackgroundresource = 0; mbackgrounddrawable = drawable; If (mdecor! = NULL) {mdecor. setwindowbackground (drawable );}}}//...}
Decorview classThis class is the internal class of the phonewindow class.
Note: This class is a subclass of framelayout and a subclass of phonewindow. This class is used to expand the functions of common framelayout. More specifically, it can be called decoration, such as adding a titlebar and a scroll bar on the titlebar. Most importantly, it is the root view of all application windows.
As follows:
Decorview Root View Structure
The source file (Part) is as follows:
Private final class decorview extends framelayout {//... // handle touch events @ override public Boolean ontouchevent (motionevent event) {return onintercepttouchevent (event );}//...}
To make an inappropriate analogy, the window class is equivalent to a painting (abstract concept, which we do not know). phonewindow is a landscape painting of Mr. Qi Baishi (specific concept, we know who it is and what it is), and decorview is the specific content of the landscape painting (there are mountains, water, trees, various interfaces ). Decorview is displayed on phonewindow.
After the system (usually activitymanagerservice) configures relevant parameters for starting an activity (including the activity object and window object information), it calls back the oncreate () method of the activity, in this example, we set the display interface of the activity by setting the setcontentview () method class, thus paving the way for the entire call chain. The call process for the three constructor methods of setcontentview () is essentially the same. We will analyze the setcontentview (intresid) method.
Step 1. activity. setcontentview (INT resid)This method is in the activity class.
This method is only a simple callback window object, specifically the setcontentview () method of the phonewindow object.
Public void setcontentview (INT layoutresid) {getwindow (). setcontentview (layoutresid);} public window getwindow () {return mwindow; // window object, essentially a phonewindow object}
Step 2. phonewindow. setcontentview ()This method is in the phonewindow class.
@ Override public void setcontentview (INT layoutresid) {// whether the setcontentview method is called for the first time. If this is the first call, the mdecor and mcontentparent objects are empty if (mcontentparent = NULL) {installdecor ();} else {mcontentparent. removeallviews ();} mlayoutinflater. inflate (layoutresid, mcontentparent); final callback cb = getcallback (); If (CB! = NULL) {CB. oncontentchanged ();}}
This method first determines whether the mcontentparent is obtained by setcontentview (), that is, whether the setcontentview () method of the phonewindow object is called for the first time. If this is the first call, the installdecor () method is called. Otherwise, all child views of the mcontentparent are removed. Finally, convert the resource file to the view tree through the layoutinflater object and add it to the mcontentparent view.
PS: therefore, in an application, we can call setcontentview () multiple times to display our interface.
Step 3 phonewindow. installdecor ()This method is in the phonewindow class.
Private void installdecor () {If (mdecor = NULL) {// If mdecor is null, A decor object mdecor = generatedecor (); mdecor is created. setdescendantfocusability (viewgroup. focus_after_descendants); mdecor. setisrootnamespace (true);} If (mcontentparent = NULL) {// The generatelayout () method is modified according to the window style, select the corresponding modifier layout file // and assign the framelayout with the ID of content (Android: Id = "@ + ID/content") to mcontentparent = generatelayout (mdecor ); //...}
First, this method first checks whether the mdecor object is null. If not empty, call generatedecor () to create a decorview (this class is
Framelayout subclass, that is, a viewgroup view); The generatedecor () method is prototype:
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }
Second, continue to judge whether the mcontentparent object is null. If not, call the generatelayout () method to create the mcontentparent object.
The generatelayout () method is as follows:
Protected viewgroup generatelayout (decorview decor) {// apply data from current theme. //... 1. Set the features value based on the Android: theme = "" of requestfreature () and activity nodes. // 2. Set the features value based on the specified features value, that is, the specific style attribute, select a different window modifier layout file int layoutresource; // window modifier layout file int features = getlocalfeatures (); // system. out. println ("features: 0x" + integer. tohexstring (features); If (Features & (1 <feature_left_icon) | (1 <feature_right _ Icon )))! = 0) {If (misfloating) {layoutresource = com. android. internal. r. layout. dialog_title_icons;} else {layoutresource = com. android. internal. r. layout. screen_title_icons;} // system. out. println ("title icons! ");} Else if (Features & (1 <feature_progress) | (1 <feature_indeterminate_progress )))! = 0) {// special case for a window with only a progress bar (and title ). // XXX need to have a no-title version of Embedded Windows. layoutresource = com. android. internal. r. layout. screen_progress; // system. out. println ("progress! ");}//... // 3 select the window decoration layout file, add it to the decorview object, and specify the mcontentparent value view in = mlayoutinflater. inflate (layoutresource, null); decor. addview (in, new viewgroup. layoutparams (match_parent, match_parent); viewgroup contentparent = (viewgroup) findviewbyid (id_android_content); If (contentparent = NULL) {Throw new runtimeexception ("window couldn't find content container View");} If (Features & (1 <featu Re_indeterminate_progress ))! = 0) {progressbar progress = getcircularprogressbar (false); If (progress! = NULL) {progress. setindeterminate (true) ;}//... return contentparent ;}
This method will do the following:
1. Select different window layout files (Root View) for the window based on the style modification type of the window ). These window decoration layout files specify a viewgroup view used to store the activity custom Layout file. Generally, the ID of framelayout is: Android: Id = "@ Android: ID/content ". For example, the window modifier types include fullscreen (full screen) and notitlebar (excluding the title bar. There are two types of window modifier selected:
① Specify requestfeature () to specify the window modifier. The phonewindow object calls the getlocalfeature () method to obtain the value;
② Configure the corresponding attribute for our activity, that is, Android: theme = "". The phonewindow object calls the getwindowstyle () method to obtain the value.
For example, you can use the following method to hide the title bar: requestwindowfeature (window. feature_no_title); or configure the XML Attribute for the activity: Android: theme = "@ Android: style/theme. notitlebar ".
PS: Therefore, the requestfeature () method must be called before setcontentview in the activity.
After determining the window style, select the layout files corresponding to the style. These layout files are located in frameworks/base/CORE/RES/layout/. Typical window layout files include:
R. layout. dialog_titile_icons R. layout. screen_title_icons
R. layout. screen_progress R. layout. dialog_custom_title
R. layout. dialog_title
R. layout. screen_title // The most common activity window modifier layout File
R. layout. screen_simple // full screen activity window layout File
Analyze the most common window layout file of an activity, R. layout. screen_title:
<!-- 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"> <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>
The layout file is simple. A linearlayout contains two sub-framelayout views. The first framelayout is used to display the title bar (titlebar). The textview view ID is title (Android: Id = "@ Android: ID/Title "); the second framelayout is used to display the parent view of the layout file of our activity. The framelayoutid is content (Android: Id =" @ Android: ID/content ").
Full screen window layout file R. layout. screen_simple:
This is an optimized layout for a screen, with the minimum set of features enabled. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/content" android:fitsSystemWindows="true" android:foregroundInsidePadding="false" android:foregroundGravity="fill_horizontal|top" android:foreground="?android:attr/windowContentOverlay" />
This layout file only has one framelayout to display the layout file of our activity. The framelayout ID is Android: Id = "@ Android: ID/content"
2. After determining the window decoration layout file in the previous step, mdecor adds the view corresponding to the window layout as the root view and obtains the view with the ID of content, assign it to the mcontentparent object, that is, the second framelayout we mentioned earlier.
At last, after the mdecor and mcontentparent objects are generated, add our activity layout file directly to the mcontentparent parent view.
Return to step 2. phonewindow. setcontentview (). This method is in the phonewindow class.
@Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else { mContentParent.removeAllViews(); } mLayoutInflater.inflate(layoutResID, mContentParent); final Callback cb = getCallback(); if (cb != null) { cb.onContentChanged(); } }
The whole process mainly involves how to add the layout file of the activity to the window. The above process can be summarized:
1. Create a decorview object as the root view of the entire application window.
2. Create different window decoration layout files and obtain the location of the activity layout file, which is specified by framelayout with the ID of content in the window decoration layout file.
3. Add the layout file of the activity to framelayout with the ID of content.
Finally, when AMS (activitymanagerservice) prepares a resume activity, it calls back the handleresumeactivity () method of the activity. This method calls the makevisible method of the activity, the mdecor view family we just created is displayed.
The handleresumeactivity () method is prototype: Located in the activitythread class.
// When the system resume an activity, call this method final void handleresumeactivity (ibinder token, Boolean clearhide, Boolean isforward) {activityrecord r = javasmresumeactivity (token, clearhide );//... if (R. activity. mvisiblefromclient) {R. activity. makevisible ();}}
The makevisible () method is prototype: Located in the activity class.
Void makevisible () {If (! Mwindowadded) {ViewManager WM = getwindowmanager (); // obtain the windowmanager object WM. addview (mdecor, getwindow (). getattributes (); mwindowadded = true;} mdecor. setvisibility (view. visible); // make it display}
The next step is to notify windowmanagerservice of the created window so that it can display the window on the screen.
For more information, see instructor Deng fanping's blog "android surface [1]".
References:
Add layout file/view to Window Process Analysis in Android ---- start with setcontentview ()