Activity setContentView(int layoutResID) 发生了什么
来源:互联网 发布:苍南哪有淘宝培训 编辑:程序博客网 时间:2024/05/22 11:45
在写activity时,一般用setContentView 来设置界面。
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
getWindow().setContentView(layoutResID);
initActionBar();
}
/**
* Retrieve the current {@link android.view.Window} for the activity.
* This can be used to directly access parts of the Window API that
* are not available through Activity/Screen.
*
* @return Window The current window, or null if the activity is not
* visual.
*/
public Window getWindow() {
return mWindow;
}
* Retrieve the current {@link android.view.Window} for the activity.
* This can be used to directly access parts of the Window API that
* are not available through Activity/Screen.
*
* @return Window The current window, or null if the activity is not
* visual.
*/
public Window getWindow() {
return mWindow;
}
获取当前activity的 window对象,看一下在哪里给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) {
attachBaseContext(context);
mFragments.attachActivity(this);
//给当前activity赋值 window
mWindow = PolicyManager.makeNewWindow(this);
//设置回调 就是常用的各种事件,键盘之类的回调
mWindow.setCallback(this);
//设置设置一个自定义的布局填充方法 后面会看到
mWindow.getLayoutInflater().setPrivateFactory(this);
//键盘输入
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
mFragments.attachActivity(this);
//给当前activity赋值 window
mWindow = PolicyManager.makeNewWindow(this);
//设置回调 就是常用的各种事件,键盘之类的回调
mWindow.setCallback(this);
//设置设置一个自定义的布局填充方法 后面会看到
mWindow.getLayoutInflater().setPrivateFactory(this);
//键盘输入
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
attach 这个是在activity 被反射 构建实例的之后调用这个方法。
看 PolicyManager这个类
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
try {
//这里通过反射 实例化 Policy 类
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
} catch (InstantiationException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
}
}
// Cannot instantiate this class
private PolicyManager() {}
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
public static LayoutInflater makeNewLayoutInflater(Context context) {
return sPolicy.makeNewLayoutInflater(context);
}
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
return sPolicy.makeNewFallbackEventHandler(context);
}
}
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
try {
//这里通过反射 实例化 Policy 类
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
} catch (InstantiationException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
}
}
// Cannot instantiate this class
private PolicyManager() {}
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
public static LayoutInflater makeNewLayoutInflater(Context context) {
return sPolicy.makeNewLayoutInflater(context);
}
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
return sPolicy.makeNewFallbackEventHandler(context);
}
}
Policy 构建 PhoneWindow对象
//构建的是PhoneWindow对象
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
PhoneWindow 的 setContentView 方法
@Override
public void setContentView(int layoutResID) {
//设置界面布局,初始化根容器
if (mContentParent == null) {
installDecor(); //会初始化跟布局并设置顶部导航
} else {
//设置view时,会首先将以后的view 移除掉
mContentParent.removeAllViews();
}
//同样使用LayoutInflater 填充布局
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//通知内容已经改变
cb.onContentChanged();
}
}
public void setContentView(int layoutResID) {
//设置界面布局,初始化根容器
if (mContentParent == null) {
installDecor(); //会初始化跟布局并设置顶部导航
} else {
//设置view时,会首先将以后的view 移除掉
mContentParent.removeAllViews();
}
//同样使用LayoutInflater 填充布局
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//通知内容已经改变
cb.onContentChanged();
}
}
接着看 LayoutInflater 是怎么填充布局的
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
if (DEBUG) System.out.println("INFLATING from resource: " + resource);
XmlResourceParser parser = getContext().getResources().getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
if (DEBUG) System.out.println("INFLATING from resource: " + resource);
XmlResourceParser parser = getContext().getResources().getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = mContext;
View result = root;
try {
// Look for the root node.
//找到根节点,开始节点
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
//如果没有开始节点,认为xml错误 抛出异常
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
//获取跟节点名称
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
//merge的填充方式
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs, false);
} else {
// Temp is the root view that was found in the xml
View temp; //一直觉得这个命名比较奇怪,但是也是一种根节点的方式
if (TAG_1995.equals(name)) {
temp = new BlinkLayout(mContext, attrs);
} else { //正常节点 创建一个根view
temp = createViewFromTag(root, name, attrs);
}
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
//填充所有的子控件
rInflate(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
return result;
}
}
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = mContext;
View result = root;
try {
// Look for the root node.
//找到根节点,开始节点
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
//如果没有开始节点,认为xml错误 抛出异常
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
//获取跟节点名称
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
//merge的填充方式
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs, false);
} else {
// Temp is the root view that was found in the xml
View temp; //一直觉得这个命名比较奇怪,但是也是一种根节点的方式
if (TAG_1995.equals(name)) {
temp = new BlinkLayout(mContext, attrs);
} else { //正常节点 创建一个根view
temp = createViewFromTag(root, name, attrs);
}
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
//填充所有的子控件
rInflate(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
return result;
}
}
View createViewFromTag(View parent, String name, AttributeSet attrs) {
if (name.equals("view")) { //获取没有命名空间的view 名字
name = attrs.getAttributeValue(null, "class");
}
if (DEBUG) System.out.println("******** Creating view: " + name);
try {
View view;
//这个mFractory 都是可以被设置成自定义的实现方式,
// 他继承Factory这个类需要实现onCreateView方法 返回一个view,可以看作是一个暴露出去自定义的一种实现方式
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, mContext, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, mContext, attrs);
} else {
view = null;
}
//和 Factory一样 只是参数不哟样
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);
}
if (view == null) { //如果这时候 view 已然为null 说明没有自定义实现 需要自己来做
//这里如果不包含点 说明是系统级别的返回,如果包含说明是自定义的 ,用不用的命名空间,就是没有前缀
if (-1 == name.indexOf('.')) {
//这个方法 最终会补一个前缀调用 createView(name, "android.view.", attrs); 方法和下面走的是同一个方法 只不过是自己加了个前缀
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
}
if (DEBUG) System.out.println("Created view is: " + view);
return view;
} catch (InflateException e) {
throw e;
} catch (ClassNotFoundException e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
} catch (Exception e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
}
}
if (name.equals("view")) { //获取没有命名空间的view 名字
name = attrs.getAttributeValue(null, "class");
}
if (DEBUG) System.out.println("******** Creating view: " + name);
try {
View view;
//这个mFractory 都是可以被设置成自定义的实现方式,
// 他继承Factory这个类需要实现onCreateView方法 返回一个view,可以看作是一个暴露出去自定义的一种实现方式
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, mContext, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, mContext, attrs);
} else {
view = null;
}
//和 Factory一样 只是参数不哟样
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);
}
if (view == null) { //如果这时候 view 已然为null 说明没有自定义实现 需要自己来做
//这里如果不包含点 说明是系统级别的返回,如果包含说明是自定义的 ,用不用的命名空间,就是没有前缀
if (-1 == name.indexOf('.')) {
//这个方法 最终会补一个前缀调用 createView(name, "android.view.", attrs); 方法和下面走的是同一个方法 只不过是自己加了个前缀
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
}
if (DEBUG) System.out.println("Created view is: " + view);
return view;
} catch (InflateException e) {
throw e;
} catch (ClassNotFoundException e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
} catch (Exception e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
}
}
*/
//采用递归的方式将所有自节点填充完毕
void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
//循环填充
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
//根据不同类型的节点 采用不用的填充方式
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) { //include 节点不能未根元素
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, parent, attrs);
} else if (TAG_MERGE.equals(name)) { //merge 节点必须为根节点
throw new InflateException("<merge /> must be the root element");
} else if (TAG_1995.equals(name)) {
final View view = new BlinkLayout(mContext, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
viewGroup.addView(view, params);
} else {
//走创建createViewFromTag方法
final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
//给上一级添加子view
viewGroup.addView(view, params);
}
}
//布局填充结束 会调用次方法
if (finishInflate) parent.onFinishInflate();
}
//采用递归的方式将所有自节点填充完毕
void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
//循环填充
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
//根据不同类型的节点 采用不用的填充方式
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) { //include 节点不能未根元素
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, parent, attrs);
} else if (TAG_MERGE.equals(name)) { //merge 节点必须为根节点
throw new InflateException("<merge /> must be the root element");
} else if (TAG_1995.equals(name)) {
final View view = new BlinkLayout(mContext, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
viewGroup.addView(view, params);
} else {
//走创建createViewFromTag方法
final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
//给上一级添加子view
viewGroup.addView(view, params);
}
}
//布局填充结束 会调用次方法
if (finishInflate) parent.onFinishInflate();
}
这样 一个布局就填充结束了 ,这个还是比较简单的,代码逻辑也不复杂,但是view的绘制流程,和事件分发传递过程 就比较复杂了。
0 0
- Activity setContentView(int layoutResID) 发生了什么
- Activity中布局资源layoutResId在setContentView加载过程分析
- Android的Activity中setContentView到底经历了什么?
- Activity中的setContentView方法到底做了什么?
- setContentView到底做了什么
- SetContentView都做了什么
- Activity-setContentView(int resId)源码分析
- 最近发生了什么...
- 发生什么了??
- 预处理发生了什么
- setContentView究竟干了什么?(API21)
- setContentView() 究竟都做了什么?
- 今天发生了什么阿?
- new之后发生了什么?
- Hello World 发生了什么?
- 不管昨天发生了什么````
- 行走后发生了什么
- Hello World 发生了什么?
- javascript的基础学习笔记
- Android Jni编写
- js的get set, 构造函数,匿名函数,prototype(原型)
- 堆的操作
- JavaWeb开发-tomcat目录详解
- Activity setContentView(int layoutResID) 发生了什么
- 易语言学习第十三课
- 生成一颗具有关键字从1到2^(H+1)-1且高为H的理想平衡二叉树
- VIM学习(1)
- 刷新后页面回归原处
- 2016.4.23 浙江省赛题解
- 自定义CheckBox和RadioButton的样式
- SurfaceView的个人理解
- Longest Substring Without Repeating Characters