Activity 从加载布局文件到显示的过程分析
2017-12-06 16:43
387 查看
在Activity 生命周期函数执行过程详解中介绍了ActivityThread、Instrumentation、ActivityManagerService启动activity的过程,本文主要介绍Activity从加载布局文件到显示的过程。
间接调用了getWindow()的setContentView()函数,来看看getWindow()
来看看mWindow是什么时候初始化的
在activity的attach()函数中初始化,是一个PhoneWindow,那接着而看看PhoneWindow的setContentView()方法
mContentParent为null时先调用 installDecor(),然后在通过mLayoutInflater.inflate(layoutResID, mContentParent);进行设置,先来看看installDecor()
DecorView为null时调用generateDecor()进行初始化DecorView,mContentParent为null时调用generateLayout(mDecor)初始化mContentParent,然后设置标题,若不显示标题则隐藏。
先来看看generateDecor()
只是进行初始化DecorView,接着看generateLayout(mDecor)
我们再回到PhoneWindow的setContentView()函数中
通过转载网上的一张图片来说明
![](https://img-blog.csdn.net/20171206164251892?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQWRvYmVTb2xv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
1.activity在onCreate()中间接调用PhoneWindow的setContentView()
2.PhoneWindow根据主题进行初始化DecorView以及title和ContentParent
3.将对应的布局文件设置到ContentParent中
在Activity 生命周期函数执行过程详解中我们知道,View的显示是在handleResumeActivity()中处理的,那么我们接着看handleResumeActivity()
1.将DecorView设置为Invisible
2.将DecorView加入到ViewManger中
3.通过activity的makeVisible()进行显示
来看看makeVisible()函数
设置DecorView为visible,而调用setVisibility会间接触发view的绘制流程,然后更新界面。
至于view的绘制流程以及ViewManager用单独的文章介绍。
SetContentView
在activity的onCreate()生命周期函数中,会调用setContentView()来设置我们的布局文件,先来了解下setContentView()函数public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID);//调用了getWindow() initWindowDecorActionBar(); }
间接调用了getWindow()的setContentView()函数,来看看getWindow()
public Window getWindow() { return mWindow; }
来看看mWindow是什么时候初始化的
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) { attachBaseContext(context); ... mWindow = new PhoneWindow(this); ... }
在activity的attach()函数中初始化,是一个PhoneWindow,那接着而看看PhoneWindow的setContentView()方法
@Override public void setContentView(int layoutResID) { // before this happens. 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 { mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
mContentParent为null时先调用 installDecor(),然后在通过mLayoutInflater.inflate(layoutResID, mContentParent);进行设置,先来看看installDecor()
private void installDecor() { //mDecor为null,进行初始化 if (mDecor == null) { mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } } //mContentParent为null,进行初始化 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 (decorContentP cc3e arent != 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) && !mIsStartingWindow) { invalidatePanelMenu(FEATURE_ACTION_BAR); } } else { // mContentParent不为null 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); } } } } }
DecorView为null时调用generateDecor()进行初始化DecorView,mContentParent为null时调用generateLayout(mDecor)初始化mContentParent,然后设置标题,若不显示标题则隐藏。
先来看看generateDecor()
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }
只是进行初始化DecorView,接着看generateLayout(mDecor)
protected ViewGroup generateLayout(DecorView decor) { //...省略代码 //通过主题加载不同的布局文件 View in = mLayoutInflater.inflate(layoutResource, null); //设置DecorView decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) in; //获取contentParent ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); //...省略代码 return contentParent; }
我们再回到PhoneWindow的setContentView()函数中
public void setContentView(int layoutResID) { 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 { //布局文件被设置到ContentParent mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
通过转载网上的一张图片来说明
1.activity在onCreate()中间接调用PhoneWindow的setContentView()
2.PhoneWindow根据主题进行初始化DecorView以及title和ContentParent
3.将对应的布局文件设置到ContentParent中
在Activity 生命周期函数执行过程详解中我们知道,View的显示是在handleResumeActivity()中处理的,那么我们接着看handleResumeActivity()
handleResumeActivity()
直接看handleResumeActivity()代码是如何展示view的final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { //省略部分代码 if (r.window == null && !a.mFinished && willBeVisible) { //获取PhoneWindow r.window = r.activity.getWindow(); //获取PhoneWindow的DecorView View decor = r.window.getDecorView(); //DecorView设置为不显示INVISIBLE decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; wm.addView(decor, l); } //省略部分代码 if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); //将decorview加入到加入到ViewManager中 wm.updateViewLayout(decor, l); } } r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { //显示view r.activity.makeVisible(); } } }
1.将DecorView设置为Invisible
2.将DecorView加入到ViewManger中
3.通过activity的makeVisible()进行显示
来看看makeVisible()函数
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
设置DecorView为visible,而调用setVisibility会间接触发view的绘制流程,然后更新界面。
至于view的绘制流程以及ViewManager用单独的文章介绍。
相关文章推荐
- Android布局文件的加载过程分析:Activity.setContentView()源码分析
- Android布局文件的载入过程分析:Activity.setContentView()源代码分析
- Android中 将布局文件/View显示至手机屏幕的 整个过程分析
- 源码分析setContentView加载布局文件的过程
- Activity是如何加载布局文件的?
- Android中将布局文件/View添加至窗口过程分析
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起(写的很好,这个不是从启动app说的,说的是UI是怎么绘制的)
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android6.0 按键kl文件加载过程分析
- Android中将xml布局文件转化为View树的过程分析(上)
- React-Native系列Android——Javascript文件加载过程分析
- 【转载】Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android Honeycomb加载键盘布局文件过程
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- 从地址栏输入URL到页面加载显示的过程分析
- [置顶] Activity布局加载流程源码分析(II)
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- spring源码分析-配置文件加载过程