在写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的绘制流程,和事件分发传递过程 就比较复杂了。