安卓setContentView

首先进入activity中找到setContentView方法:

public void setContentView(@LayoutRes int layoutResID) {
     getWindow().setContentView(layoutResID);
     initWindowDecorActionBar();
}

找到三个setContentView方法,我们发现内部都是调用getWindow()的setContentView方法,getWindow()得到一个在Activity的attach方法中初始化的PhoneWindow对象mWindow

进入PhoneWindow类可知,该类继承Window类,Window类是抽象类,注释如下

/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */
 public class PhoneWindow extends Window implements MenuBuilder.Callback {

百度翻译:顶级视图和行为策略的基础抽象类。此类的实例被用做顶级视图添加到window manager中。提供了UI策略规则,如背景background、title区域、默认key处理等
该抽象类存在的唯一的实现是android.view.PhoneWindow,当你需要一个window的时候可以用到它。

在这里插入图片描述
每个Activity持有一个Window对象,也就是PhoneWindow,PhoneWindow又持有了一个DecorView对象,DecorView对象所加载的布局资源中含有TextView(R.id.title)和FrameLayout(R.id.content)

回到PhoneWindow中,找到setContentView方法

@Override
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 {
	//将layoutResID解析后添加到mContentParent的子view树里
	mLayoutInflater.inflate(layoutResID, mContentParent);
	}
    	...
    	...
    	...
}

首先来看mContentParent

ViewGroup mContentParent;

mContentParent 是被放置在window窗口的视图,可能是mDecor 本身,或者是mDecor 的子视图

private DecorView mDecor;

DecorView 是window窗口顶级视图,包含窗口装饰
当mContentParent == null时执行installDecor()方法

private void installDecor() {
		...
	if (mDecor == null) {
		//不存在,创建
		mDecor = generateDecor(-1);
         ...
	} else {
		//存在,将此PhoneWindow传递给mDecor
		mDecor.setWindow(this);
	}
	if (mContentParent == null) {
		//创建基础试图框架mContentParent ,并在其中为mDecor设置布局资源
		mContentParent = generateLayout(mDecor);
			...
		//decor_content_parent是基础布局中最外层布局的id,其中的根布局ActionBarOverlayLayout
		//实现了DecorContentParent 接口
		final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
			R.id.decor_content_parent);
		if (decorContentParent != null) {
		mDecorContentParent = decorContentParent;
		//设置Window的一些回调、title等
		mDecorContentParent.setWindowCallback(getCallback());
           		 ...
           		 ...
         	  	 ...
		} else {
			//设置title,根据FEATURE_NO_TITLE设置是否显示
			mTitleView = findViewById(R.id.title);
			if (mTitleView != null) {
			if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
				final View titleContainer = findViewById(R.id.title_container);
					if (titleContainer != null) {
						titleContainer.setVisibility(View.GONE);
					} else {
						mTitleView.setVisibility(View.GONE);
					}
				mContentParent.setForeground(null);
			} else {
				mTitleView.setText(mTitle);
			}
		}
	}

	if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
		mDecor.setBackgroundFallback(mBackgroundFallbackResource);
	}
           ...........
}

现在可知installDecor方法的作用有两点:
一、将PhoneWindow绑定给DecorView;
二、调用generateLayout方法.

protected DecorView generateLayout(DecorView decor) {
			...
			...
		//根据activity是否设置ActionBar,为layoutResource赋值不同布局screen_action_bar或者screen_title
		//screen_action_bar内部包含R.id.content(Framelayout)和一个ActionBarContainer布局
		//screen_title内部包含R.id.content(Framelayout)和一个被Framelayout包裹的R.id.title(TextView)
		} 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;
		}
            ...
            ...
		//为mDecor加载布局资源layoutResource
		mDecor.startChanging();
		mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
       		 
		//contentParent 获取该布局中的R.id.conten(FrameLayout)
		ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
		if (contentParent == null) {
			throw new RuntimeException("Window couldn't find content container view");
		}
       		 ...
       		 ...
		//将mDecor布局中的R.id.conten(FrameLayout)作为基础布局框架返回
		return contentParent;
}

generateLayout方法的主要作用
1、创建基础视图框架布局mContentParent ;
2、对mDecor加载资源布局。
其中mContentParent 是mDecor布局中的子view(R.id.content)

在setContentView方法中执行完installDecor方法后会执行mLayoutInflater.inflate(layoutResID, mContentParent);将传递进来的layoutResID布局资源解析添加到mContentParent (com.android.internal.R.id.content)的子view树里,到这里就完成了setContentView方法的布局加载。

猜你喜欢

转载自blog.csdn.net/QQsongQQ/article/details/83023949