//调用了 window 的 setContentView,在 attach 中给 mWindow=new PhoneWindow(this);
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
复制代码
/**@methord installDecor() 为 activity 添加根布局DecorView(mDecor),全部的事件都是经过它从 activity 传到 view 上的。并解析 activity 的theme初始化 titleview 和过场动画。 *@field mContentParent 根据 theme 的不一样inflate 几种布局加到DecorView上,在上一个方法中同时初始化mDecor和mContentParent @field FEATURE_CONTENT_TRANSITIONS判断是否有5.0共享元素过场动画,没有直接调用了 inflate **/
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);//处理makeSceneTransitionAnimation用的
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();//调用了requestFitSystemWindows
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {//调用设置 contentChange 的回调
cb.onContentChanged();
}
}
复制代码
这里直接调用了LayoutInflater.inflate,然而LayoutInflater又是经过getSystemService(LAYOUT_INFLATER_SERVICE)
得到的,在 activity 中的 mBase 又是从哪里来的呢,在 startActivity 后启动了新的Activity,在 Instrumentation的execStartActivity中ActivityManagerNative.getDefault().startActivity()
使用ActivityManagerProxy.startActivity经过IBinder调用了系统进程。并无找到 activity 是怎么 new 出来的java
换个套路,因为 activity历来不复写构造方法,mBase 赋值的地方只有一个,attachBaseContext();
复写这个方法并在里面抛出异常。在一层层的去分析,log代表在ActivityThread中收到了 handler,并在performLaunchActivity直接调用了 attach,在 attach 中第一行就是设置 context 的方法android
public ContextThemeWrapper() {
super(null);//咱们继承 activity 的时候并无调用 super 的构造,确定不是在这里初始化的
}
复制代码
at android.app.Activity.attach(Activity.java:6641)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2629)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2768)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1481)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6153)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)
复制代码
//activity.attach 的 context 参数是这样初始化的
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
try {
displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
} catch (RemoteException e) {
}
//就是这里 new ContextImpl()。这个类中找 getSystemService
ContextImpl appContext = ContextImpl.createActivityContext( this, r.packageInfo, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
......
return baseContext;
}
复制代码
/**在 contextImpl 中只有一行代码 SystemServiceRegistry.getSystemService(),进入到SystemServiceRegistry是这样实现的 *@params SYSTEM_SERVICE_FETCHERS 这个参数中保存了 getSystemService的全部能够用的 service,在这个类中有一个静态方法块,添加service *@params ServiceFetcher 是一个接口 **/
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
//静态代码块中,是这样注册的,PhoneLayoutInflater就是实际调用的 view 解析器。
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
复制代码
到这里整个应用每次获取的 LayoutInflate仍是同样的。可是在每一个 activity 中把 LayoutInflate 的 hashcode 输出缺是不同的。由于在 ContextThemeWrapper.getSystemService 还调用了cloneInContext缓存
//在PhoneLayoutInflater中是这样实现的,全部每一个 activity 使用的inflate并非同一个
public LayoutInflater cloneInContext(Context newContext) {
return new PhoneLayoutInflater(this, newContext);
}
复制代码
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
final XmlResourceParser parser = res.getLayout(resource);//建立了 xml 解析器
try {//最终解析的方法
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
复制代码
//这里解析的是 xml 的第一层
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");//保存 log 到系统中
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
// Empty
}//按理说只执行一次 next,这样写多是防止 parser 在前面的代码已经向后移动了,当前的 type 并无在 START 的位置
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription() + ": No start tag found!");
}
final String name = parser.getName();
//判断 是否是 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");
}//由于 merge 不是 view,不建立根节点必需要添加到root 上
//根据root 初始化布局
rInflate(parser, root, inflaterContext, attrs, false);
} else {//经过 string和 xml 的属性建立view 的逻辑
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {//若是设置了root 要建立出 layoutParams
params = root.generateLayoutParams(attrs);//根据 attrs 建立 layoutParams
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflateChildren(parser, temp, attrs, true);//和rInflate不一样的是,这里是加到了createViewFromTag的 view 上了。
if (root != null && attachToRoot) {//把createViewFromTag加到了root 上,比 merge 多了一层view
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;//若是传入root 而且addview 了返回 root,不然返回建立的 view
}
}
} catch (XmlPullParserException e) {
final InflateException ie = new InflateException(e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (Exception e) {
final InflateException ie = new InflateException(parser.getPositionDescription() + ": " + e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} finally {
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
return result;
}
}
复制代码
rInflateChildren 和 rInflate 方法的差别是少了一个 context 的参数,由于,merge 的 root 的 attr 不必定和 xml 里面用同一个。全部须要单独传 context。bash
这里解析xml 除了根标签的子标签,每一层子标签会递归一层app
void rInflate(XmlPullParser parser, View parent, Context context, 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) {//当解析到最后一个 tag 的时候结束
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {//view 下有 <requestFocus /> 请求焦点
parseRequestFocus(parser, parent);
} else if (TAG_TAG.equals(name)) {// <tag android:id="@+id/mytag" android:value="@string/mytag_value" />给 view 添加多个 tag
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {//解析到了 include
if (parser.getDepth() == 0) {//不能把 xml 的第一个标签就声明为 include
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);//只是合并 include标签和 layout 的属性逻辑,不作分析
} else if (TAG_MERGE.equals(name)) {//xml 中 merge 必须是根元素
throw new InflateException("<merge /> must be the root element");
} else {//普通的 view
final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);//只要继承了 ViewGroup 都会复写这个方法。
rInflateChildren(parser, view, attrs, true);//递归调用 rInflate 直到完成解析
viewGroup.addView(view, params);
}
}
if (finishInflate) {//当全部的子 view 解析完成调用
parent.onFinishInflate();
}
}
复制代码
createViewFromTag是经过xml标签生成 view 的重点方法。
复制代码
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) {
if (name.equals("view")) {//view 的 className 支持两种传入方式,读取 class 属性值
name = attrs.getAttributeValue(null, "class");
}
//include设置了theme 这里是 false,不然都会使用 context 的属性
if (!ignoreThemeAttr) {
final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0) {
context = new ContextThemeWrapper(context, themeResId);
}
ta.recycle();
}
if (name.equals(TAG_1995)) {//继承了 FragmentLayout,闪烁的效果,不多用
// Let's party like it's 1995!
return new BlinkLayout(context, attrs);
}
try {
View view;
if (mFactory2 != null) {//设置了自定义的 view 建立方式。这个接口就是我想设置的
view = mFactory2.onCreateView(parent, name, context, attrs);
} else if (mFactory != null) {//和 Factory2相比这个里面的onCreateView方法。少 parent 参数
view = mFactory.onCreateView(name, context, attrs);
} else {
view = null;
}
if (view == null && mPrivateFactory != null){//系统的注释很到位,这个是为手机厂家留的,for use by framework
view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view == null) {//若是用户和手机厂商没有设置 factory,就使用系统默认的解析
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {//TextView,ImageView这些系统控件,在调用的时候不是全 className,这个方法里拼接了 createView(name, "android.view.", attrs)
view = onCreateView(parent, name, attrs);
} else {//自定义 view
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
return view;
} catch (InflateException e) {
throw e;
} catch (ClassNotFoundException e) {
final InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + name, e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (Exception e) {
final InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + name, e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
}
}
复制代码
若是须要自定义 View 的实例化须要调用 setFactory2或setFactory,这两个方法差异不大,这两个方法若是某一个调用过一次了,若是再次调用会抛出异常,`new FactoryMerger(factory, factory, mFactory, mFactory2)`由于只能设置一次,不使用反射,后面两个参数确定是null,前面两个都是设置的factory。若是调用setFactory2会拿到 parent。setFactory则不会。
复制代码
createView()方法中 经过反射获取 class,并获取构造方法,并使用 sConstructorMap 缓存为后面加载一样的 View 使用,view = constructor.newInstance(args);
反射构造传入 context 和 attr 建立一个实例,这里只使用了两个构造参数的方法 mConstructorSignature = new Class[] {Context.class, AttributeSet.class}
。在 View 的源码中能够看到两个参数的构造方法调用了4个参数的构造:ide
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this(context);
.........
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case com.android.internal.R.styleable.View_background: ...
break;
case com.android.internal.R.styleable.View_padding: ...
break;
case com.android.internal.R.styleable.View_paddingLeft: ...
break;
case com.android.internal.R.styleable.View_paddingTop: ...
break;
case com.android.internal.R.styleable.View_paddingRight: ...
break;
.........
复制代码
点进源码看到它继承了 FragmentActivity 在 onCreate 方法的第一行AppCompatDelegate delegate = getDelegate(); delegate.installViewFactory();
修改了 Factory,xml 中生命的 TextView 都被实例化成了 AppCompatTextView。就有了RippleDrawable的效果oop
public final View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs, boolean inheritContext,boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
......
switch (name) {
case "TextView":
view = new AppCompatTextView(context, attrs);
break;
case "ImageView":
view = new AppCompatImageView(context, attrs);
break;
case "Button":
view = new AppCompatButton(context, attrs);
break;
case "EditText":
view = new AppCompatEditText(context, attrs);
break;
case "Spinner":
view = new AppCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new AppCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new AppCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new AppCompatRadioButton(context, attrs);
break;
case "CheckedTextView":
view = new AppCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new AppCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new AppCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new AppCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new AppCompatSeekBar(context, attrs);
break;
}
if (view == null && originalContext != context) {
view = createViewFromTag(context, name, attrs);
}
return view;
}
复制代码
add by dingshaoran布局