Refer to the article
- Preliminary understanding of Window system – Simple book
- AMS – Activity management Activity start and destroy process – simple book
What is a Window
Window, as its name implies, means window. In Android, the final drawing of graphics is done through Window. The Window is the View manager. Whether it’s an Activity,Toast, or Dialog, it ends up attaching its View to the Window.
Window creation process
Window creation in the Activity
The onCreate method is not the first to be called in the Activity lifecycle. The first method actually called is the attach method. In the ActivityThread. Java# performLaunchActivity method, the acitivty instance is created by calling attach and then onCreate.
The code in ActivityThread.java is as follows (note: the code below has been truncated to preserve only the rough flow code)
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; . ContextImpl appContext = createBaseContextForActivity(r); Activity activity =mInstrumentation.newActivity( cl, component.getClassName(), r.intent); Application app = r.packageInfo.makeApplication(false, mInstrumentation);
Configuration config = new Configuration(mCompatConfiguration);
appContext.setOuterContext(activity);
activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken); .if (r.isPersistable()) {
// The system can save data after shutdown.
The Acitivty property persistableMode needs to be configured in the manifest file
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {// This is where you gomInstrumentation.callActivityOnCreate(activity, r.state); }...return activity;
}
Copy the code
The internal flow of the callActivityOnCreate method is callActivityOnCreate->Activity#performCreate->Activity#onCreate. Next, let’s look at the attach method
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
/ / activityConfigCallback listens for configuration change, this parameter was introduced to ViewRootImpl# setActivityConfigCallback
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// called when the status bar, picture in picture, etc., mode changes
mWindow.setWindowControllerCallback(this);
// This is passed in as window.callback
// Interface related callback calls, window property changes, contentView changes, etc
// And event distribution
mWindow.setCallback(this);
// Call onWindowDismissed when the window disappears. Finish is called in the Activity
mWindow.setOnWindowDismissedCallback(this);
// Set the constructor for the root View, Activity#onCreateView
mWindow.getLayoutInflater().setPrivateFactory(this);
// Set the input mode display status to unspecified
if(info.softInputMode ! = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); }// I don't know what it is
if(info.uiOptions ! =0) {
mWindow.setUiOptions(info.uiOptions);
}
// Get the current UI thread
mUiThread = Thread.currentThread();
// mUiThread = mMainThread
mMainThread = aThread;
/ / structure
mInstrumentation = instr;
/* Token is a binder proxy, a token class inherited from iApplicationToken. Stub, which identifies an activity token with only one method, getName */
mToken = token;
// Ident is 0
mIdent = ident;
// The current application object
mApplication = application;
// Incoming intent
mIntent = intent;
// Caller information
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
// Default title
mTitle = title;
// Null (Fragment, deprecated)
mParent = parent;
// Do not know the effect
mEmbeddedID = id;
/ / I don't know
mLastNonConfigurationInstances = lastNonConfigurationInstances;
// mVoiceInteractor voice interaction
if(voiceInteractor ! =null) {
if(lastNonConfigurationInstances ! =null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this.this, Looper.myLooper()); }}// setWindowManager passes in WindowManger
// WindowManager is an interface whose implementation is WindowManagerImp
// WindowMangerImpl is a proxy class, which ultimately performs various window operations through WindowMnagerGlobal. Windows ManagerGlobal is an in-process singleton class.
// FLAG_HARDWARE_ACCELERATED Determines whether hardware acceleration is enabled for your Activity
// For acceleration, refer to the articlemWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! =0);
// If there is mParent, the DecorView of the current Activity window is not treated as the top-level window, but as the parent container determines how it should be displayed
// Otherwise, the Activity's DecorView will act as the top-level Window
if(mParent ! =null) {
mWindow.setContainer(mParent.getWindow());
}
// Get the WindowManagerImpl object corresponding to Acitivty
mWindowManager = mWindow.getWindowManager();
// The current configuration, such as vertical and horizontal direction, etc
mCurrentConfig = config;
/ / set the bitmap mode, specific refer to https://developer.android.google.cn/training/wide-color-gamut?hl=zh-cn
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
enableAutofillCompatibilityIfNeeded();
}
Copy the code
First of all, you can see that in attach method you just new a PhoneWindow instance,
mWindow = new PhoneWindow(this, window, activityConfigCallback);
Copy the code
The specific PhoneWindow is created as follows
/** * Constructor for main window of an activity. */
public PhoneWindow(Context context, Window preservedWindow, ActivityConfigCallback activityConfigCallback) {
this(context);
// Only main activity windows use decor context, all the other windows depend on whatever
// context that was given to them.
mUseDecorContext = true;
if(preservedWindow ! =null) {
mDecor = (DecorView) preservedWindow.getDecorView();
mElevation = preservedWindow.getElevation();
mLoadElevation = false;
mForceDecorInstall = true;
// If we're preserving window, carry over the app token from the preserved
// window, as we'll be skipping the addView in handleResumeActivity(), and
// the token will not be updated as for a new window.
getAttributes().token = preservedWindow.getAttributes().token;
}
// Even though the device doesn't support picture-in-picture mode,
// an user can force using it through developer options.
boolean forceResizable = Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE);
mActivityConfigCallback = activityConfigCallback;
}
Copy the code
Mwindow.setcallback (this) sets the Window Callback, which is mostly related to input events such as touch. The specific Callback method is as follows:
public interface Callback {
public boolean dispatchKeyEvent(KeyEvent event);
public boolean dispatchKeyShortcutEvent(KeyEvent event);
public boolean dispatchTouchEvent(MotionEvent event);
public boolean dispatchTrackballEvent(MotionEvent event);
public boolean dispatchGenericMotionEvent(MotionEvent event);
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event); .Copy the code
There are two points to analyze at setWindowManager
getSystemService
Acquired objectsetWindowManager
Internal operation of
mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! =0);
Copy the code
1. GetSystemService Obtain the object
Context is passed in as a ContextImple object, and its internal implementation of getSystemService is as follows
@Override
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
...
}
return SystemServiceRegistry.getSystemService(this, name);
}
Copy the code
In the SystemServiceRegistry class, a Windows manager impl object is statically built, So clearly the setWindowManager in the Active # Attach method is passing in a Windows Manager ImpL object.
static{
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
}
/** * Statically registers a system service with the context. * This method must be called during static initialization only. */
private static <T> void registerService(@NonNull String serviceName,
@NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}
Copy the code
2. Internal operations of setWindowManager
The setWindowManager method creates a WindowManagerImpl object to manage the Window and uses the WindowManagerImpl instance passed in as its mParentWindow property
Obviously the WindowManagerImpl instance obtained in getSystemService is the mParentWindow property of all other Acitivty WindowManagerImpl objects.
The window.java code looks like this
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
Copy the code
The windowManagerImp.java code looks like this:
public final class WindowManagerImpl implements WindowManager {
@UnsupportedAppUsage
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@VisibleForTesting
public final Context mContext;
private final Window mParentWindow;
private IBinder mDefaultToken;
public WindowManagerImpl(Context context) {
this(context, null);
}
private WindowManagerImpl(Context context, Window parentWindow) {
mContext = context;
mParentWindow = parentWindow;
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
return newWindowManagerImpl(displayContext, mParentWindow); }... }Copy the code
This code describes the creation of the Window in the Activity. Next, look at the process by which a View is added to the Window
The process of adding a View to a Window
The process of adding a View to a Window in an Activity
As soon as the Window is added, the onCreate method is called, and the View is added to the onCreate. In the first paragraph of the article begins with performLaunchActivity method in code can be seen, after call attach method is called after mInstrumentation. CallActivityOnCreate method, After calling the Activity#performCreate method, go to the Activity#onCreate method
Instrumentation. Java# callActivityOnCreate code:
public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
Copy the code
The code for activity.java #performCreate is as follows:
final void performCreate(Bundle icicle, PersistableBundle persistentState) {...if(persistentState ! =null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);// go to onCreate}... }Copy the code
The creation of a DecorView
First the setContentView method is called in Activity#onCreate
The active #setContentView method actually calls the Window#setContentView method
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
Copy the code
GetWindow ().setContentView
PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
privateDecorView mDecor; ViewGroup mContentParent; .@Override
public void setContentView(int layoutResID) {
/ / code 1
if (mContentParent == null) {
installDecor();
} else if(! hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
/ / code 2
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
/ / code 3
if(cb ! =null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true; }}Copy the code
- The first thing you’ll see is code 1
mContentParent
Whether it isnull
, such asnull
The call
MContentParent is an important property in PhoneWindow. MContentParent is the Window container for View content, which can be mDecor itself or a subview of mDecor. (mDecor is a top-level View, and DecorView inherits the FragmentLayout class)
-
Code 2 parses the passed layoutResID through the mLayoutInflater and puts it inside the mContentParent.
-
Code 3 gets the Callback object set and calls onContentChanged() to notify the View that the content has changed.
The Callback object is the Callback object set in the Activity#attach method. OnContentChanged onContentChanged() is a Callback method in the Activity This method is called when the layout of the Activity changes, that is, when the setContentView() or addContentView() methods have finished executing. For example, the findViewById() methods of various views in the Activity can be placed in this method. Of course, in general, most developers get the object instance in the onCreate method by executing setContentView.
Next, look at the installDecor method
InstallDecor implementation
private void installDecor(a) {
mForceDecorInstall = false;
/ / code 1
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if(! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! =0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); }}else {
mDecor.setWindow(this);
}
/ / code 2
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeFrameworkOptionalFitsSystemWindows();
final DecorContentParent decorContentParent =
(DecorContentParent) mDecor.findViewById(R.id.decor_content_parent);
if(decorContentParent ! =null) { mDecorContentParent = decorContentParent; mDecorContentParent.setWindowCallback(getCallback()); . }else{ mTitleView = findViewById(R.id.title); . }... }}Copy the code
- At code 1, call
generateDecor
Method to generate amDecor
Object,DecorView
Will be called in the constructor ofsetWindow
Methods,PhoneWindow
Object passed in.
GenerateDecor method
- This is called in code 2
generateLayout
generatemContentParent
object
The generateDecor code below doesn’t have much to say
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, this);
if(mTheme ! = -1) {
context.setTheme(mTheme);// set the theme. The theme set by AndroidManifest is assigned to ActivityThread#performLaunchActivity}}}else {//
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
Copy the code
GenerateLayout code is as follows
protected ViewGroup generateLayout(DecorView decor) {
// Set the theme according to the current theme
TypedArray a = getWindowStyle();
// Check if it is a suspension window
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false); .// Determine whether to add actionBar and title according to theme
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.requestFeature(FEATURE_ACTION_BAR); . WindowManager.LayoutParams params = getAttributes();// Whether to draw the status bar and navigation bar background
if(! mIsFloating) {if(! targetPreL && a.getBoolean( R.styleable.Window_windowDrawsSystemBarBackgrounds,false)) {
setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
}
if(mDecor.mForceWindowDrawsBarBackgrounds) { params.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; }}// Whether to draw StatusBar and navigationBar as bright themes
if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
// Whether the current mode is banged to get the banged mode
if (a.hasValue(R.styleable.Window_windowLayoutInDisplayCutoutMode)) {
int mode = a.getInt(R.styleable.Window_windowLayoutInDisplayCutoutMode, -1);
if (mode < LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|| mode > LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
throw new UnsupportedOperationException("Unknown windowLayoutInDisplayCutoutMode: "+ a.getString(R.styleable.Window_windowLayoutInDisplayCutoutMode)); } params.layoutInDisplayCutoutMode = mode; }...// Is the current input mode
if(! hasSoftInputMode()) { params.softInputMode = a.getInt( R.styleable.Window_windowSoftInputMode, params.softInputMode); }// Window animation
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(
R.styleable.Window_windowAnimationStyle, 0);
}
// The rest are only done if this window is not embedded; otherwise,
// the values are inherited from our container.
if (getContainer() == null) {
if (mBackgroundDrawable == null) {
if (mFrameResource == 0) {
mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
}
if(a.hasValue(R.styleable.Window_windowBackground)) { mBackgroundDrawable = a.getDrawable(R.styleable.Window_windowBackground); }}if (a.hasValue(R.styleable.Window_windowBackgroundFallback)) {
mBackgroundFallbackDrawable =
a.getDrawable(R.styleable.Window_windowBackgroundFallback);
}
if (mLoadElevation) {
mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
}
mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
}
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
/ / code 1
// System.out.println("Features: 0x" + Integer.toHexString(features));
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_PROGRESS) | (1<< FEATURE_INDETERMINATE_PROGRESS))) ! =0
&& (features & (1 << FEATURE_ACTION_BAR)) == 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 = R.layout.screen_progress;
// System.out.println("Progress!" );
} else if ((features & (1<< FEATURE_CUSTOM_TITLE)) ! =0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
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 if ((features & (1<< FEATURE_ACTION_MODE_OVERLAY)) ! =0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!" );
}
mDecor.startChanging();
/ / code 2
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
// ID_ANDROID_CONTENT = com.android.internal.R.id.content
// findViewById is from mDecor to findView objects
/ / code 3
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1<< FEATURE_INDETERMINATE_PROGRESS)) ! =0) {
ProgressBar progress = getCircularProgressBar(false);
if(progress ! =null) {
progress.setIndeterminate(true); }}// If getContainer == null, it is a top-level View. Normally, the Activity Window corresponds to the top-level Window.
// Set the background color and title color
if (getContainer() == null) {
mDecor.setWindowBackground(mBackgroundDrawable);
final Drawable frame;
if(mFrameResource ! =0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if(mTitle ! =null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
Copy the code
- At code 1, according to
feature
As well aswindow
Type to determine the introducedmContentParent
Layout. Generally, the layout of full-screen display isR.layout.screen_simple
.R.layout.screen_simple
There was aandroid:id="@android:id/content"
theFrameLayout
Layout (regardlesslayoutResource
The corresponding layout file is that one, both of themandroid:id="@android:id/content"
theFrameLayout
). - At code 2, call
DecorView#onResourcesLoaded
Pass in the ID of the layout and parse to generate oneDecorView
View object propertiesmContentRoot
. - At code 3,
findViewById
The implementation of theWindow.java
, its final callmDecor
thefindViewById
Method, searchmDecor
Of the corresponding ID underView
.ID_ANDROID_CONTENT
The value ofcom.android.internal.R.id.content
. Obviously,findViewById
To obtain theViewGroup
Object ismDecor
Under themContentRoot
With id@android:id/content
theFrameLayout
Object.
Next, code analysis. First, R.l ayout. Screen_simple (/ frameworks/base/core/res/res/layout/screen_simple XML) layout code, as shown below, this can’t.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<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:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="? android:attr/windowContentOverlay" />
</LinearLayout>
Copy the code
Take a look at the DecorView#onResourcesLoaded code.
class DecorView{
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
if(mBackdropFrameRenderer ! =null) {... }/ / code 1
mDecorCaptionView = createDecorCaptionView(inflater);
// at code 2
final View root = inflater.inflate(layoutResource, null);
if(mDecorCaptionView ! =null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
/ / code 3
// Put it below the color views.
addView(root, 0.newViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mContentRoot = (ViewGroup) root; initializeElevation(); }}Copy the code
- One is created in code 1
mDecorCaptionView
Object,createDecorCaptionView
According to its English notesFree-floating overlapping Windows require a title.We have no Free floating Windows require a captionActivity
的setContentView
In the process,mDecorCaptionView == null
, so the code will go to code 3 - Code 2 According to
layoutResource
, parse the resource file and generate the correspondingView
, i.e.,R.layout.screen_simple
(or otherwise) analyticallyView
. - Code 3 parses the layout file
root
Object, add toDecorView
The son ofView
Let’s look at the PhoneView#generateLayout method implementation of the findViewById method
class Window{
@Nullable
public View findViewById(@IdRes int id) {
returngetDecorView().findViewById(id); }}Copy the code
FindViewById looks for a ViewGroup object with ID R.D.C. Tent from mDecor. The PhoneView mContentParent object is a child ViewGroup with id Content under the mContentRoot in the DecorView.
Let’s go back to the PhoneView#setContentView method and look at code 2
mLayoutInflater.inflate(layoutResID, mContentParent);
Copy the code
LayoutResID is the layout file id value passed in by Activity#setContentView. The layout passed in by Activity#setContentView is obviously a child View of the mContentParent.
With that said, we can now summarize an inclusion relationship for activities, PhoneWindows, and decorViews.
One: That thing with DecorView
But this is just the creation of the DecorView, the View has not been added to the Window yet!!
Add a DecorView to the PhoneView
Immediately after executing the create phase in the ActivityThread’s handleLaunchActivity, start the resume process by calling the handleResumeActivity method. The handleResumeActivity method is as follows
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {...// Code 1 calls the Activity's onResume indirectly
finalActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); .if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// Set code 2 to invisible until the DecorView is added to the Window
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
// Code 3 sets the type of the Window. TYPE_BASE_APPLICATION indicates that the Window is an application-level Window, at the bottom of the application Window.
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if(impl ! =null) { impl.notifyChildRebuilt(); }}if (a.mVisibleFromClient) {
if(! a.mWindowAdded) { a.mWindowAdded =true;
// Code 4 adds decor to Window
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.a.onWindowAttributesChanged(l); }}// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if(! willBeVisible) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true; }... }Copy the code
Code 4 calls the WindowManager addView method. The WindowManager implementation class is WindowManagerImpl, and WindowManagerImpl#addView calls the WindowManagerGlobal addView method. Windowmanagerglobar #addView is an example of an onKeyDown problem with Android 9 and Android 9.