一时兴起, 想看看Activity怎么回事, 然后就开始跟代码, 从 setContentView(int layoutResID) 开始:
Activity.java
<span style="font-size:18px;"> public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}</span>
<span style="font-size:18px;"> public Window getWindow() {
return mWindow;
}</span>
这个mWindow是啥咧, 还费了点劲.
final void attach(...) {
...
mWindow = PolicyManager.makeNewWindow(this);
...
}
PolicyManager.java
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
sPolicy又是啥子呢
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 {
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);
}
}
发现通过反射来实例化的, 但是本地的SDK中又没有这个包
但是在http://androidxref.com找到了相应的源码.
Policy.java
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
看到这里才发现,原来activity里面也是用LayoutInflater来加载的
LayoutInflater.java
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();
}
}
Resources.java
public XmlResourceParser getLayout(int id) throws NotFoundException {
return loadXmlResourceParser(id, "layout");
}
/*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
throws NotFoundException {
synchronized (mAccessLock) {
TypedValue value = mTmpValue;
if (value == null) {
mTmpValue = value = new TypedValue();
}
getValue(id, value, true);
if (value.type == TypedValue.TYPE_STRING) {
return loadXmlResourceParser(value.string.toString(), id,
value.assetCookie, type);
}
throw new NotFoundException(
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ Integer.toHexString(value.type) + " is not valid");
}
}
/*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
int assetCookie, String type) throws NotFoundException {
if (id != 0) {
try {
// These may be compiled...
synchronized (mCachedXmlBlockIds) {
// First see if this block is in our cache.
final int num = mCachedXmlBlockIds.length;
for (int i=0; i<num; i++) {
if (mCachedXmlBlockIds[i] == id) {
//System.out.println("**** REUSING XML BLOCK! id="
// + id + ", index=" + i);
return mCachedXmlBlocks[i].newParser();
}
}
// Not in the cache, create a new block and put it at
// the next slot in the cache.
XmlBlock block = mAssets.openXmlBlockAsset(
assetCookie, file);
if (block != null) {
int pos = mLastCachedXmlBlockIndex+1;
if (pos >= num) pos = 0;
mLastCachedXmlBlockIndex = pos;
XmlBlock oldBlock = mCachedXmlBlocks[pos];
if (oldBlock != null) {
oldBlock.close();
}
mCachedXmlBlockIds[pos] = id;
mCachedXmlBlocks[pos] = block;
//System.out.println("**** CACHING NEW XML BLOCK! id="
// + id + ", index=" + pos);
return block.newParser();
}
}
} catch (Exception e) {
NotFoundException rnf = new NotFoundException(
"File " + file + " from xml type " + type + " resource ID #0x"
+ Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
}
throw new NotFoundException(
"File " + file + " from xml type " + type + " resource ID #0x"
+ Integer.toHexString(id));
}
这两个方法就是返回一个XmlResourceParser对象, 先在缓存中查找有无已存在的对象, 有就直接返回, 没有就实例化一个并添加到缓存.
下面先看一下getValue()中做了啥
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
if (found) {
return;
}
throw new NotFoundException("Resource ID #0x"
+ Integer.toHexString(id));
}
AssetManager.java
/*package*/ final boolean getResourceValue(int ident,
int density,
TypedValue outValue,
boolean resolveRefs)
{
int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
if (block >= 0) {
if (outValue.type != TypedValue.TYPE_STRING) {
return true;
}
outValue.string = mStringBlocks[block].get(outValue.data);
return true;
}
return false;
}
private native final int loadResourceValue(int ident, short density, TypedValue outValue,
boolean resolve);
结果还是跟到了native方法, 这个方法大概就是获取资源,并存储到outValue中, 然后返回值就是能否找到该资源并获取值.
上面的获取到parser后继续inflate(parser, root, attachToRoot);
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
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
}
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("**************************");
}
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 {
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;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return result;
}
}
这里加载完了得到view, 非常麻烦的过程, 想想要把xml解析为view也是巨大的工作量阿, 然而
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
直接传入一个view就能是程序效率高很多, 这样的话, 在写界面时, 尽量实现用代码实现view.
再继续往下面看
ViewGroup.java
public void addView(View child, LayoutParams params) {
addView(child, -1, params);
}
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
注释说的比较清楚, 调用requestLayout(), 会重新布局, 并且还调用了invalidate(true)
public void requestLayout() {
if (mMeasureCache != null) mMeasureCache.clear();
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
// Only trigger request-during-layout logic if this is the view requesting it,
// not the views in its parent hierarchy
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null && viewRoot.isInLayout()) {
if (!viewRoot.requestLayoutDuringLayout(this)) {
return;
}
}
mAttachInfo.mViewRequestingLayout = this;
}
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
mPrivateFlags |= PFLAG_INVALIDATED;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
mAttachInfo.mViewRequestingLayout = null;
}
}
之后会把view添加到内部的一个view数组中
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
mTransition.cancel(LayoutTransition.DISAPPEARING);
}
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
if (mTransition != null) {
mTransition.addChild(this, child);
}
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
if (preventRequestLayout) {
child.mLayoutParams = params;
} else {
child.setLayoutParams(params);
}
if (index < 0) {
index = mChildrenCount;
}
addInArray(child, index);
// tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
}
AttachInfo ai = mAttachInfo;
if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
if (ai.mKeepScreenOn) {
needGlobalAttributesUpdate(true);
}
ai.mKeepScreenOn = lastKeepOn;
}
if (child.isLayoutDirectionInherited()) {
child.resetRtlProperties();
}
onViewAdded(child);
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
if (child.isImportantForAccessibility() && child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
addInArray仅仅是把view加入到一个childview列表中
protected void onViewAdded(View child) {
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(this, child);
}
}
到这里就是view的绘制过程, 写累了, 查资料时看到一篇博文, 正好是讲如何绘制view, 在此就直接引用了