从setContentView方法分析Android加载布局流程

PS一句:当初你所逃避的问题终会在未来的某一天重新出现在你面前,因此,当你第一次遇到它时,请不要逃避。

相信很多初学者对XML布局怎么加载到Activity上并且显示在手机屏幕上很好奇吧?今天我们就从经常使用的方法

setContentView来从源码分析一下XML布局是怎么加载到当前Activity上的。

Activity#setContentView

我们知道,Activity是在onCreate方法中使用setContentView方法来加载布局的,那么它内部的源码是怎么实现的呢?

Setp 1

处于好奇,我们进入了Activity的源码,找到setContentView方法如下:

(int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();}

setContentView方法实现很简单,里面调用两个方法,我们这里分析第一个方法:

getWindow().setContentView(layoutResID);

getWindow()得到一个Window对象 mWindow ,Window是一个抽象类,用来描述Activity视图最顶端的窗口显示和行为操作。Window是

一个抽象类,那么里面的setContentView(layoutResID)是一个抽象方法,并没有具体的实现,既然Window是一个抽象类,那么

在Activity里面就有一个Window抽象类的实现,我们查找代码发现 mWindow对象赋值方法如下:

mWindow = PolicyManager.makeNewWindow(this);Step 2

Look the fuck resoure code,继续看看 PolicyManager类

{String POLICY_IMPL_CLASS_NAME =31″com.android.internal.policy.impl.Policy”;IPolicy sPolicy;{{38Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);39sPolicy = (IPolicy)policyClass.newInstance();40} catch (ClassNotFoundException ex) {RuntimeException(42POLICY_IMPL_CLASS_NAME + ” could not be loaded”, ex);43} catch (InstantiationException ex) {RuntimeException(45POLICY_IMPL_CLASS_NAME + ” could not be instantiated”, ex);46} catch (IllegalAccessException ex) {RuntimeException(48POLICY_IMPL_CLASS_NAME + ” could not be instantiated”, ex);49}50 }More PolicyManager() {}Window More makeNewWindow(Context context) {57return sPolicy.makeNewWindow(context);58 }

地 57 行 sPolicy对象是有第 38,39行通过类路径”com.android.internal.policy.impl.Policy“生成的,那么我们在源码中找到 Policy类,在此类中找到了如下方法:

public Window makeNewWindow(Context context) {return new PhoneWindow(context);}

由此可见,我们终于找到Activity类中的 mWindow对象的实现类了,就是PhoneWindow类。

Setp 3

从源码发现,PhoneWindow类就是抽象类Window的实现类。那么 setContentView方法的实现也在这个类里面了,

到PhoneWindow类发现,setContentView方法实现如下:

(int layoutResID) {(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 {mLayoutInflater.inflate(layoutResID, mContentParent);}final Callback cb = getCallback();if (cb != null && !isDestroyed()) {cb.onContentChanged();}}

首先判断mContentParent是否为null,mContentParent是什么呢?接下来会分析,一开始条件成立,进入installDecor()方法。

Setp 4

到installDecor()方法里,实现如下:

() {if (mDecor == null) {mDecor = generateDecor();mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}}if (mContentParent == null) {mContentParent = generateLayout(mDecor);// Set up decor part of UI to ignore fitsSystemWindows if appropriate.mDecor.makeOptionalFitsSystemWindows();final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent);if (decorContentParent != null) {mDecorContentParent = decorContentParent;mDecorContentParent.setWindowCallback(getCallback());if (mDecorContentParent.getTitle() == null) {mDecorContentParent.setWindowTitle(mTitle);}final int localFeatures = getLocalFeatures();for (int i = 0; i < FEATURE_MAX; i++) {if ((localFeatures & (1 << i)) != 0) {mDecorContentParent.initFeature(i);}}mDecorContentParent.setUiOptions(mUiOptions);if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||(mIconRes != 0 && !mDecorContentParent.hasIcon())) {mDecorContentParent.setIcon(mIconRes);} else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&mIconRes == 0 && !mDecorContentParent.hasIcon()) {mDecorContentParent.setIcon(getContext().getPackageManager().getDefaultActivityIcon());mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;}if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||(mLogoRes != 0 && !mDecorContentParent.hasLogo())) {mDecorContentParent.setLogo(mLogoRes);}PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);if (!isDestroyed() && (st == null || st.menu == null)) {invalidatePanelMenu(FEATURE_ACTION_BAR);}} else {mTitleView = (TextView)findViewById(R.id.title);if (mTitleView != null) {mTitleView.setLayoutDirection(mDecor.getLayoutDirection());if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {View titleContainer = findViewById(R.id.title_container);if (titleContainer != null) {titleContainer.setVisibility(View.GONE);} else {mTitleView.setVisibility(View.GONE);}if (mContentParent instanceof FrameLayout) {((FrameLayout)mContentParent).setForeground(null);}} else {mTitleView.setText(mTitle);}}}if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {mDecor.setBackgroundFallback(mBackgroundFallbackResource);}(hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {if (mTransitionManager == null) {final int transitionRes = getWindowStyle().getResourceId(R.styleable.Window_windowContentTransitionManager,0);if (transitionRes != 0) {final TransitionInflater inflater = TransitionInflater.from(getContext());mTransitionManager = inflater.inflateTransitionManager(transitionRes,mContentParent);} else {mTransitionManager = new TransitionManager();}}mEnterTransition = getTransition(mEnterTransition, null,R.styleable.Window_windowEnterTransition);mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,R.styleable.Window_windowReturnTransition);mExitTransition = getTransition(mExitTransition, null,R.styleable.Window_windowExitTransition);mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,R.styleable.Window_windowReenterTransition);mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,R.styleable.Window_windowSharedElementEnterTransition);mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,USE_DEFAULT_TRANSITION,R.styleable.Window_windowSharedElementReturnTransition);mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,R.styleable.Window_windowSharedElementExitTransition);mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,USE_DEFAULT_TRANSITION,R.styleable.Window_windowSharedElementReenterTransition);if (mAllowEnterTransitionOverlap == null) {mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(R.styleable.Window_windowAllowEnterTransitionOverlap, true);}if (mAllowReturnTransitionOverlap == null) {mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(R.styleable.Window_windowAllowReturnTransitionOverlap, true);}if (mBackgroundFadeDurationMillis < 0) {mBackgroundFadeDurationMillis = getWindowStyle().getInteger(R.styleable.Window_windowTransitionBackgroundFadeDuration,DEFAULT_BACKGROUND_FADE_DURATION_MS);}if (mSharedElementsUseOverlay == null) {mSharedElementsUseOverlay = getWindowStyle().getBoolean(R.styleable.Window_windowSharedElementsUseOverlay, true);}}}}空虚无聊的时候就读书,但一定得有自己的生活目标和计划。

从setContentView方法分析Android加载布局流程

相关文章:

你感兴趣的文章:

标签云: