├── ActivityThread.md
├── ActivityThread.mindnode
├── QuickLook
│ └── Preview.jpg
├── contents.xml
├── style.mindnodestyle
│ ├── contents.xml
│ └── metadata.plist
└── viewState.plist
├── Activity的启动流程.md
├── BlinkLayout.md
├── LayoutInflater-2.md
├── LayoutInflater-3.md
├── LayoutInflater.md
├── Learned.md
├── ProcessRecord.md
├── README.md
├── Space.md
├── SystemServer.md
├── ViewRootImpl.md
├── ViewStub.md
├── ZygoteInit.md
├── activity-setcontentview.md
├── ask-myself.md
├── context-getsystemservice.md
├── done_list.md
├── fresco
├── Fresco.md
└── Fresco.mdj
├── imgs
├── LayoutInflate-attach2root.gliffy
├── RTFSC.mdj
├── SystemServiceRegistry.png
└── retrofit.gliffy
├── important-classes.md
├── intro-activitythread.md
├── invalidate-and-postinvalidate.md
├── libraries
├── leakcanary
│ └── LeakCanary.md
└── retrofit
│ └── how-retrofit-works.md
├── startactivity-flow.md
└── where-is-app's-entrance.md
/ActivityThread.md:
--------------------------------------------------------------------------------
1 | # ActivityThread
2 |
3 | This manages the execution of the main thread in an
4 | application process, scheduling and executing activities,
5 | broadcasts, and other operations on it as the activity
6 | manager requests.
7 |
8 |
9 | 简单释义:ActivityThread 运行在 App 进程的主线程上,负责安排并执行 ActivityManagerService 对activities broadcasts 的操作请求。
10 |
11 |
12 | 显然ActivityThread是一个AMS的命令执行者。很多非常重要的操作比如 Activity 的创建,Activity 的生命周期,都在ActivityThread中执行。
13 |
14 | ActivityThread 与 AMS 的通信是跨进程的,通过 ApplicationThread 这个 Binder 来通信的。
15 |
16 |
17 | ## ActivityThread 究竟是不是主线程?
18 |
19 | ActivityThread 在很多文章中常被称为 主线程。
20 |
21 | 这个说法并不准确,因为其实它本身并不是一个线程,只是主线程调用了AactivityThread的main方法,所以我觉得把 ActivityThread 称作『主线程的入口』会更加合适一些。
22 |
23 | 不过在 Activity的源码中有一个ActivityThread类型的成员:`/*package*/ ActivityThread mMainThread;` ,这个变量名表示了 ActivityThread 是`mainThread`。
24 |
25 | 细细想来主线程对于 App开发者来说是隐藏的,所以拿 ActivityThread 来表示 主线程倒也无可厚非。
26 |
27 | 所以我觉得虽然 ActivityThread本身并不是一个线程,但是用它来表示主线程倒也没什么,自己心里清楚即可。
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ActivityThread.mindnode/QuickLook/Preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/ActivityThread.mindnode/QuickLook/Preview.jpg
--------------------------------------------------------------------------------
/ActivityThread.mindnode/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/ActivityThread.mindnode/contents.xml
--------------------------------------------------------------------------------
/ActivityThread.mindnode/style.mindnodestyle/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/ActivityThread.mindnode/style.mindnodestyle/contents.xml
--------------------------------------------------------------------------------
/ActivityThread.mindnode/style.mindnodestyle/metadata.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/ActivityThread.mindnode/style.mindnodestyle/metadata.plist
--------------------------------------------------------------------------------
/ActivityThread.mindnode/viewState.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/ActivityThread.mindnode/viewState.plist
--------------------------------------------------------------------------------
/Activity的启动流程.md:
--------------------------------------------------------------------------------
1 | # Activity的启动流程
2 |
3 |
4 | 妈的 老子不信搞不懂。
5 |
6 | Activity的启动流程涉及到 进程的创建 Application的创建 ActivityStack 的创建 Activity 的创建
7 |
8 |
9 | 涉及到的类有:
10 |
11 | - Context 通常是我们 startActivity 的第一步,具体的实现类是 ContextImpl。
12 | - ActivityManagerService
13 | - ActivityThread
14 | - ActivityThread.H 是一个运行在主线的Handler,负责把 ApplicationThread 从 AMS 拿来的通知转换到主线程,并调用 ActivityThread 相应的方法。
15 | - ActivityThread.ApplicationThread 是一个实现了 IApplicationThread 的Binder类,是 ActivityThread 与 AMS 交互通信的媒介。AMS 通过它来告知 ActivityThread 该做什么。它最后会把 AMS 的通知都交给 ActivityThread.H 转换成 Message,转到 ActivityThread 去执行。
16 | - Instrumentation 负责创建Activity,并调用 Activity 的生命周期 eg: mInstrumentation.newActivity ,mInstrumentation.callActivityOnCreate
17 | - ActivityStackSupervisor
18 |
19 |
20 | //todo 详细的分析
21 |
22 |
23 | 大致内容记录一下
24 |
25 | 太复杂了,吃不消。。。。。。
26 |
27 |
28 | ContextImpl.startActivity/Activity.startActivity
29 | => ActivityThread.mInstrumentation.execStartActivity
30 | => ActivityManagerNative.startActivity (IActivityManagerNative 的代理ActivityManagerProxy)
31 | => ActivityManagerProxy.startActivity
32 | => ActivityManagerService.startActivity
33 | => ActivityManagerService.startActivityAsUser
34 | => ActivityStackSupervisor.startActivityMayWait
35 | => ActivityStackSupervisor.startActivityLocked
36 | => ActivityStackSupervisor.startActivityUncheckedLocked
37 | => ActivityStack.startActivityLocked
38 | => ActivityStackSupervisor.resumeTopActivitiesLocked
39 | => ActivityStack.resumeTopActivitiesLocked
40 | => ActivityStack.resumeTopActivityInnerLocked
41 | .
42 | .
43 | .
44 | .
45 | => ActivityStackSupervisor.realStartActivityLocked
46 | => app.thread.scheduleLaunchActivity
47 | => ApplicationThreadProxy.scheduleLaunchActivity
48 | => ActivityThread.sendMessage
49 | => ActivityThread.mH.sendMessage & handleMessage
50 | => ActivityThread.handleLaunchActivity
51 | => performLaunchActivity
52 | => handleResumeActivity
53 |
54 | 差不多大致是这样的流程。。。。
55 |
56 | 心好累,还是有很多很多细节没有理清楚。
57 |
58 |
59 | 真正去启动 Activity 的是 ActivityStackSupervisor.realStartActivityLocked。
60 |
61 |
62 | ActivityStack或ActivityStackSupervisor 里会调用 ActivityRecod.app.thread (IApplicationThread)的 `scheduleXXXXActivity`比如 `schedulePauseActivity`
63 |
64 |
65 | [](http://blog.csdn.net/luoshengyang/article/details/6689748)
66 |
67 |
--------------------------------------------------------------------------------
/BlinkLayout.md:
--------------------------------------------------------------------------------
1 | # LayoutInflater 源码分析(四)之 闪耀的彩蛋
2 |
3 |
4 | [LayoutInflater 源码分析(一)之 inflate 深度分析](./LayoutInflater.md)
5 | [LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
6 | [LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
7 | [LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
8 |
9 |
10 | ## BlinkLayout源码分析
11 |
12 | private static class BlinkLayout extends FrameLayout
13 |
14 |
15 | 首先,我猜,你肯定不知道有这个Layout的存在!!!
16 |
17 | 因为它隐藏的非常深,是`LayoutInflater`的静态内部类,是我在看`LayoutInflater`源码的时候发现的!简直是个彩蛋!!
18 |
19 | 在这里发现的:
20 |
21 | ```
22 | if (name.equals(TAG_1995)) {
23 | // Let's party like it's 1995!
24 | return new BlinkLayout(context, attrs);
25 | }
26 | ```
27 |
28 | oh,它其实还真算是个彩蛋,似乎是为了庆祝1995年的复活节,有兴趣可以看看
29 | [reddit](https://www.reddit.com/r/androiddev/comments/3sekn8/lets_party_like_its_1995_from_the_layoutinflater/)上的讨论。
30 |
31 |
32 | blink 有 使...闪烁的意思,可以用来做一闪一闪的效果哦!!!
33 |
34 | 先上个简单的效果图看看它的效果:
35 |
36 | 
37 |
38 | 是不是很闪?
39 |
40 | 明明这么闪耀,为何要躲起来?
41 |
42 | `BlinkLayout`的使用也有些特殊,它跟`merge`、`include`这些标签一样,用标签`blink`来表示。
43 |
44 | 贴一下上图效果的XML:
45 |
46 | ```
47 |
64 | ```
65 |
66 | 非常简单!
67 |
68 | 那么它是怎么实现的呢?
69 |
70 | 接下去源码分析。
71 |
72 | ## 源码分析
73 |
74 | `BlinkLayout`的源码非常简单,只有几十行!我就全部贴出来啦!
75 |
76 | ```
77 | private static class BlinkLayout extends FrameLayout {
78 | private static final int MESSAGE_BLINK = 0x42;
79 | private static final int BLINK_DELAY = 500;
80 |
81 | private boolean mBlink;
82 | private boolean mBlinkState;
83 | private final Handler mHandler;
84 |
85 | public BlinkLayout(Context context, AttributeSet attrs) {
86 | super(context, attrs);
87 | mHandler = new Handler(new Handler.Callback() {
88 | @Override
89 | public boolean handleMessage(Message msg) {
90 | if (msg.what == MESSAGE_BLINK) {
91 | if (mBlink) {
92 | mBlinkState = !mBlinkState;
93 | // 循环调用 makeBlink
94 | makeBlink();
95 | }
96 | // 触发 dispatchDraw
97 | invalidate();
98 | return true;
99 | }
100 | return false;
101 | }
102 | });
103 | }
104 | // 发送blink指令
105 | private void makeBlink() {
106 | Message message = mHandler.obtainMessage(MESSAGE_BLINK);
107 | mHandler.sendMessageDelayed(message, BLINK_DELAY);
108 | }
109 |
110 | @Override
111 | protected void onAttachedToWindow() {
112 | super.onAttachedToWindow();
113 | // 设置为可以闪啦
114 | mBlink = true;
115 | mBlinkState = true;
116 | // 发送消息
117 | makeBlink();
118 | }
119 |
120 | @Override
121 | protected void onDetachedFromWindow() {
122 | super.onDetachedFromWindow();
123 |
124 | mBlink = false;
125 | mBlinkState = true;
126 | // 移除消息 避免内存泄漏
127 | mHandler.removeMessages(MESSAGE_BLINK);
128 | }
129 |
130 | @Override
131 | protected void dispatchDraw(Canvas canvas) {
132 | // 通过这个开关来控制是否分发绘制事件,来达到一闪一闪的效果
133 | if (mBlinkState) {
134 | super.dispatchDraw(canvas);
135 | }
136 | }
137 | }
138 | ```
139 |
140 | 从源码中可以看出,`BlinkLayout`通过Handler循环调用`invalidate()`方法,触发并控制`dispatchDraw`来做到一闪一闪的效果,默认的闪烁间隔为Handler的DELAY时间,即500毫秒。
141 |
142 |
143 | ## 小结
144 |
145 | `BlinkLayout`的使用场景或许不多,但是它的代码还是非常漂亮哒!~
146 |
147 | 如果有类似需求,仿造它的源码写一个功能更强的View也是非常简单的!
148 |
149 | 深入源码阅读是一件相对枯燥的事情,能发现这么个小彩蛋也是棒棒的,心情也美丽了些,哈哈!~~
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/LayoutInflater-2.md:
--------------------------------------------------------------------------------
1 | # LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理
2 |
3 |
4 | [LayoutInflater 源码分析(一)之 inflate 深度分析](./LayoutInflater.md)
5 | [LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
6 | [LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
7 | [LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
8 |
9 |
10 | ## 前言
11 |
12 | 继上篇[LayoutInflater 源码分析(一)](./LayoutInflater.md)
13 |
14 | 本篇继续对`LayoutInflater`进行源码分析。
15 |
16 | 目标为分析`LayoutInflater`对`include`、`merge`、`fragment`等标签的处理原理以及`onFinishInflate`的调用时机。
17 |
18 | ## merge 标签分析
19 |
20 | [上篇](./LayoutInflater.md)讲到`inflate`方法中出现 Merge 的踪迹,代码如下:
21 |
22 | ```
23 | if (TAG_MERGE.equals(name)) {
24 | if (root == null || !attachToRoot) {
25 | throw new InflateException(" can be used only with a valid "
26 | + "ViewGroup root and attachToRoot=true");
27 | }
28 | // 调用 rInflate 注意最后的参数是 false
29 | rInflate(parser, root, inflaterContext, attrs, false);
30 | }
31 | ```
32 |
33 | 所以需要看 `rInflate`方法才行。
34 |
35 | ### rInflate 深入解析
36 |
37 | ```
38 | /**
39 | * Recursive method used to descend down the xml hierarchy and instantiate
40 | * views, instantiate their children, and then call onFinishInflate().
41 | *
42 | * Note: Default visibility so the BridgeInflater can
43 | * override it.
44 | * 递归方法 实例化 View 以及它的子 View,并且调用 onFinishInflate
45 | */
46 | void rInflate(XmlPullParser parser, View parent, Context context,
47 | AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
48 |
49 | final int depth = parser.getDepth();
50 | int type;
51 | // while 循环 parser.next 遍历整个 XML
52 | while (((type = parser.next()) != XmlPullParser.END_TAG ||
53 | parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
54 |
55 | if (type != XmlPullParser.START_TAG) {
56 | continue;
57 | }
58 | //获取标签名
59 | final String name = parser.getName();
60 | //如果是 requestFocus
61 | if (TAG_REQUEST_FOCUS.equals(name)) {
62 | parseRequestFocus(parser, parent);
63 | } else if (TAG_TAG.equals(name)) {
64 | // 处理 tag
65 | parseViewTag(parser, parent, attrs);
66 | } else if (TAG_INCLUDE.equals(name)) {
67 | if (parser.getDepth() == 0) {
68 | throw new InflateException(" cannot be the root element");
69 | }
70 | // 处理 include
71 | parseInclude(parser, context, parent, attrs);
72 | } else if (TAG_MERGE.equals(name)) {
73 | // merge 里不能再有 merge 标签的
74 | throw new InflateException(" must be the root element");
75 | } else {
76 | // 如果不是特殊的标签那么走 createViewFromTag
77 | final View view = createViewFromTag(parent, name, context, attrs);
78 | final ViewGroup viewGroup = (ViewGroup) parent;
79 | final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
80 | rInflateChildren(parser, view, attrs, true);
81 | viewGroup.addView(view, params);
82 | }
83 | }
84 | // 注意这里从传递inflate传递过来的是 false!!
85 | // 从 rInflateChildren 过来的是 true!!!
86 | if (finishInflate) {
87 | parent.onFinishInflate();
88 | }
89 | }
90 | ```
91 |
92 | 从注释来看`rInflate`方法,是个 **递归方法** 实例化 View 以及它的子 View,**并且调用 `onFinishInflate`**
93 |
94 | 从源码来看,`rInflate`方法先判断特殊的标签名,优先处理:
95 | - 针对`requestFocus`标签,调用parseRequestFocus方法
96 | - 针对`tag`标签,调用 parseViewTag 方法
97 | - 针对`merge`标签则直接抛了异常,因为`merge`标签不能是子元素
98 |
99 | 很奇怪,并没有看到 `fragment` 标签的处理逻辑!
100 |
101 | 处理完特殊标签之后走到最后一个else 块中,这块代码需要注意:
102 |
103 | ```
104 | // 如果不是特殊的标签那么走 createViewFromTag 获得 view
105 | // createViewFromTag 方法的流程已经分析过了,不再多说。
106 | final View view = createViewFromTag(parent, name, context, attrs);
107 | // 注意注意 这边的 parent 是之前inflate传入的 root
108 | final ViewGroup viewGroup = (ViewGroup) parent;
109 | // 生成 paramas
110 | final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
111 | // 调用 rInflateChildren 把 view传递过去 并传了一个 true 过去
112 | rInflateChildren(parser, view, attrs, true);
113 | // 注意
114 | // 注意
115 | // 注意
116 | // 这里直接调用 viewGroup 的 addView 这也是 merge 能减少层级的根本原因
117 | viewGroup.addView(view, params);
118 | ```
119 |
120 | 这里涉及到一个方法`rInflateChildren`,其实它在上一篇中的`inflate`方法中出现过,不过我并没有去分析,所以这里讲一下。
121 |
122 | 方法实现如下:
123 |
124 | ```
125 | final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
126 | boolean finishInflate) throws XmlPullParserException, IOException {
127 | rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
128 | }
129 | ```
130 |
131 | `rInflateChildren` 是个递归方法,被用来实例化不是 `root` 的子View,实际也是调用`rInflate`方法。(所以才是递归了嘛!)
132 |
133 | 这里需要注意的是`finishInflate`,按照之前所说的流程,`rInflate`方法传递过来的`finishInflate`参数为`false`,在上一篇中`inflate`传递的参数是`true`,这关系到`onFinishInflate`的回调。
134 |
135 | 了解完`rInflateChildren`方法后,继续分析。
136 |
137 | 可以看到,在处理`merge`标签的时候,是将`merge`标签里解析出来的 View 直接 add 到了传递进来的`root`中去了,而并不会多加一层 View,从而实现减少层级的效果,这就是`merge`标签的原理所在了。
138 | 最后,由于`inflate`传递进来的`finishInflate`为 false,所以不会去调用`parent.onFinishInflate();`
139 |
140 | 到此也知晓了`LayoutInflater`是如何处理`merge`标签以及`merge`减少布局层次的原理了。
141 |
142 | ## include 标签
143 |
144 | ```
145 | private void parseInclude(XmlPullParser parser, Context context, View parent,
146 | AttributeSet attrs) throws XmlPullParserException, IOException {
147 | int type;
148 |
149 | if (parent instanceof ViewGroup) {
150 | // Apply a theme wrapper, if requested. This is sort of a weird
151 | // edge case, since developers think the overwrites
152 | // values in the AttributeSet of the included View. So, if the
153 | // included View has a theme attribute, we'll need to ignore it.
154 | final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
155 | final int themeResId = ta.getResourceId(0, 0);
156 | final boolean hasThemeOverride = themeResId != 0;
157 | if (hasThemeOverride) {
158 | context = new ContextThemeWrapper(context, themeResId);
159 | }
160 | ta.recycle();
161 | // If the layout is pointing to a theme attribute, we have to
162 | // massage the value to get a resource identifier out of it.
163 | int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
164 | if (layout == 0) {
165 | // 没有 layout 属性则抛异常
166 | final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
167 | if (value == null || value.length() <= 0) {
168 | throw new InflateException("You must specify a layout in the"
169 | + " include tag: ");
170 | }
171 | // Attempt to resolve the "?attr/name" string to an identifier.
172 | layout = context.getResources().getIdentifier(value.substring(1), null, null);
173 | }
174 |
175 | // The layout might be referencing a theme attribute.
176 | if (mTempValue == null) {
177 | mTempValue = new TypedValue();
178 | }
179 | if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
180 | layout = mTempValue.resourceId;
181 | }
182 | // 之前的代码都是处理 theme layout 属性 不多说。
183 | if (layout == 0) {
184 | // 必须指定有效的layout
185 | final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
186 | throw new InflateException("You must specify a valid layout "
187 | + "reference. The layout ID " + value + " is not valid.");
188 | } else {
189 | final XmlResourceParser childParser = context.getResources().getLayout(layout);
190 |
191 | try {
192 | final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
193 |
194 | while ((type = childParser.next()) != XmlPullParser.START_TAG &&
195 | type != XmlPullParser.END_DOCUMENT) {
196 | // Empty.
197 | }
198 |
199 | if (type != XmlPullParser.START_TAG) {
200 | throw new InflateException(childParser.getPositionDescription() +
201 | ": No start tag found!");
202 | }
203 |
204 | final String childName = childParser.getName();
205 |
206 | if (TAG_MERGE.equals(childName)) {
207 | // The tag doesn't support android:theme, so
208 | // nothing special to do here.
209 | rInflate(childParser, parent, context, childAttrs, false);
210 | } else {
211 | // 获取 被 inlcude 的 topview
212 | final View view = createViewFromTag(parent, childName,
213 | context, childAttrs, hasThemeOverride);
214 | final ViewGroup group = (ViewGroup) parent;
215 |
216 | final TypedArray a = context.obtainStyledAttributes(
217 | attrs, R.styleable.Include);
218 | final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
219 | final int visibility = a.getInt(R.styleable.Include_visibility, -1);
220 | a.recycle();
221 |
222 | // We try to load the layout params set in the tag.
223 | // If the parent can't generate layout params (ex. missing width
224 | // or height for the framework ViewGroups, though this is not
225 | // necessarily true of all ViewGroups) then we expect it to throw
226 | // a runtime exception.
227 | // We catch this exception and set localParams accordingly: true
228 | // means we successfully loaded layout params from the
229 | // tag, false means we need to rely on the included layout params.
230 | ViewGroup.LayoutParams params = null;
231 | try {// 尝试对 include 标签生成 params
232 | params = group.generateLayoutParams(attrs);
233 | } catch (RuntimeException e) {
234 | // Ignore, just fail over to child attrs.
235 | }
236 | // 如果失败 则对被 include 的 topview 处理
237 | if (params == null) {
238 | params = group.generateLayoutParams(childAttrs);
239 | }
240 | view.setLayoutParams(params);
241 | // Inflate all children. 前面已经提到过了
242 | rInflateChildren(childParser, view, childAttrs, true);
243 | // 处理 id
244 | if (id != View.NO_ID) {
245 | view.setId(id);
246 | }
247 | // 处理可见性
248 | switch (visibility) {
249 | case 0:
250 | view.setVisibility(View.VISIBLE);
251 | break;
252 | case 1:
253 | view.setVisibility(View.INVISIBLE);
254 | break;
255 | case 2:
256 | view.setVisibility(View.GONE);
257 | break;
258 | }
259 | // 把 view 添加到 group 中
260 | group.addView(view);
261 | }
262 | } finally {
263 | childParser.close();
264 | }
265 | }
266 | } else {
267 | throw new InflateException(" can only be used inside of a ViewGroup");
268 | }
269 |
270 | LayoutInflater.consumeChildElements(parser);
271 | }
272 | ```
273 |
274 | 首先判断 parent 是不是个 ViewGroup,如果不是则直接抛异常。
275 |
276 | 如果是则接下去处理 `theme` 属性以及 `layout` 属性,我们知道使用`include`标签,`layout` 属性是必须要有的。
277 |
278 | 其原因就是在源码中如果发现没有指定 `layout` 属性的话,那么会直接抛出异常。
279 |
280 | 再接下去的步骤可以看出其实跟上篇`inflate`方法类似:
281 |
282 | 1. 通过调用`createViewFromTag`解析获取被`include`的 `topview`
283 | 2. 生成 `params`,这里要注意,`include`标签可能没有宽高,会导致生成失败,如果失败则接着又对被`include`的 topview 做操作。所以使用`include`的时候,**不对它设置宽高是没有关系的**。
284 | 3. 调用`rInflateChildren`处理子View 之前已经分析过
285 | 4. 把 `include` 标签的 `id` 以及 `visibility`属性 设置给 `topview`(如果有的话)
286 | 5. `topView` 被直接 add 进 group,这样被 include 的 topView 就被加到布局里去了。
287 |
288 | ## 小结
289 |
290 | 通过阅读源码,其实 merge 以及 include 等标签处理其实并不难,而且它们的使用方法在源码中皆有体现。
291 |
292 | 稍微总结一下要点:
293 |
294 | 1. 使用 LayoutInflater 去 inflate merge 标签的时候,root 一定不能为 null,attachToRoot 也不能为 false
295 | 2. merge标签在 XML 中**必须是根元素**
296 | 3. 与 merge 标签相反,include 绝对不能是根元素,必须需要在一个 ViewGroup 中使用
297 | 4. 使用 include 标签必须指定有效的 layout 属性
298 | 5. 使用 include 标签不写宽高是没有关系的(会去解析被 include 的 layout)
299 |
300 | 到这里`merge`以及`include`已经分析完毕。
301 |
302 | 同时也看到了其他标签如`tag`、`requestFocus`的处理(很简单就不分析了),但是就是没看到`fragment`标签。
303 |
304 | 那究竟是在哪处理`fragment`标签的呢?
305 |
306 | 请看下集[LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/LayoutInflater-3.md:
--------------------------------------------------------------------------------
1 | # LayoutInflater源码分析(三)之 fragment 标签的处理
2 |
3 |
4 | [LayoutInflater 源码分析(一)之 inflate 深度分析](./LayoutInflater.md)
5 | [LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
6 | [LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
7 | [LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
8 |
9 | ## 前言
10 |
11 | 上一篇[LayoutInflater 源码分析(二)](./LayoutInflater-2.md)中分析了`LayoutInflater`对`include`以及`merge`标签的处理,但是并没有找到对`fragment`的处理痕迹。
12 |
13 | 本文将继续探索以求揭晓答案。
14 |
15 | 提一下`fragment`标签的使用方式:
16 |
17 | ```
18 |
25 | ```
26 |
27 | 注意:这属于加载 Fragment 中的**静态加载**,在 XML 中写死了 class,缺乏灵活性,实际开发中并不常用,甚至已经淘汰了,所以不推荐使用。
28 |
29 | 不过这并不妨碍对它的原理探究。
30 |
31 | ## 分析
32 |
33 | 在第一篇分析中提到了 Factory 的 Hook 机制,代码如下:
34 |
35 | ```
36 | View view;
37 | if (mFactory2 != null) {
38 | view = mFactory2.onCreateView(parent, name, context, attrs);
39 | } else if (mFactory != null) {
40 | view = mFactory.onCreateView(name, context, attrs);
41 | } else {
42 | view = null;
43 | }
44 | // mPrivateFactory 是个 FactoryMerger
45 | if (view == null && mPrivateFactory != null) {
46 | view = mPrivateFactory.onCreateView(parent, name, context, attrs);
47 | }
48 |
49 | ```
50 |
51 | 为了便于理解那些个 Factory,特意大致的画了一张类图:
52 |
53 |
54 |
55 | 注意:前面代码中的mPrivateFactory 是个 FactoryMerger 对象。
56 |
57 | 可能看到这里还是会有些茫然,不过仔细一回想我们在使用 Fragment 的时候都会继承 FragmentActivity,所以去 FragmentActivity 寻找答案感觉比较靠谱。
58 |
59 | 接下去开始分析。
60 |
61 | ## 寻找踪迹 FragmentActivity
62 |
63 | 查看了源码后发现,FragmentActivity 的继承结构如下
64 |
65 |
66 |
67 | 其实 Activity 就已经实现了 LayoutInflater.Factory2 接口,具体实现如下:
68 |
69 | ```
70 | public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
71 | // 如果不是 fragment 则调用另一个onCreateView,而它返回的是 null
72 | if (!"fragment".equals(name)) {
73 | return onCreateView(name, context, attrs);
74 | }
75 | // 如果是 fragment 标签 则交给了 mFragments
76 | return mFragments.onCreateView(parent, name, context, attrs);
77 | }
78 |
79 | public View onCreateView(String name, Context context, AttributeSet attrs) {
80 | return null;
81 | }
82 | ```
83 |
84 | 可以看到如果是 fragment 标签,则会交给一个叫 mFragments 的FragmentController类的对象。
85 |
86 | 但是需要注意的是:**Activity 并没有调用 LayoutInflater.setFactory 使之生效,所以 Activity 并不支持 fragment 的解析**。
87 |
88 | 继续看它的子类的实现。
89 |
90 | ```
91 | // Donut 好古老的版本啊~
92 | abstract class BaseFragmentActivityDonut extends Activity {
93 | @Override
94 | protected void onCreate(Bundle savedInstanceState) {
95 | if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
96 | // On pre-HC devices we need to manually install ourselves as a Factory.
97 | // On HC and above, we are automatically installed as a private factory
98 | getLayoutInflater().setFactory(this);
99 | }
100 | super.onCreate(savedInstanceState);
101 | }
102 | //重写 onCreateView
103 | @Override
104 | public View onCreateView(String name, Context context, AttributeSet attrs) {
105 | // 优先调用 dispatchFragmentsOnCreateView
106 | final View v = dispatchFragmentsOnCreateView(null, name, context, attrs);
107 | if (v == null) {
108 | return super.onCreateView(name, context, attrs);
109 | }
110 | return v;
111 | }
112 |
113 | abstract View dispatchFragmentsOnCreateView(View parent, String name,
114 | Context context, AttributeSet attrs);
115 |
116 | }
117 | // Honeycomb
118 | abstract class BaseFragmentActivityHoneycomb extends BaseFragmentActivityDonut {
119 | @Override
120 | public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
121 | final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
122 | if (v == null && Build.VERSION.SDK_INT >= 11) {
123 | // If we're running on HC or above, let the super have a go
124 | return super.onCreateView(parent, name, context, attrs);
125 | }
126 | return v;
127 | }
128 |
129 | }
130 | // FragmentActivity 并没有重写 onCreateView
131 | public class FragmentActivity extends BaseFragmentActivityHoneycomb{
132 | @Override
133 | final View dispatchFragmentsOnCreateView(View parent, String name, Context context,
134 | AttributeSet attrs) {
135 | return mFragments.onCreateView(parent, name, context, attrs);
136 | }
137 | }
138 | ```
139 |
140 | 可以看到,在`BaseFragmentActivityDonut`中调用了`setFactory`,并定义了一个`dispatchFragmentsOnCreateView`抽象方法,并在`onCreateView`里调用了它,这样就把创建 View 的工作交给了`dispatchFragmentsOnCreateView`。
141 |
142 | 接着,在 FragmentActivity 重写`dispatchFragmentsOnCreateView`,又把它交给了`mFragments`,咦,又回去了。
143 |
144 | 其实到这里已经可以知道,`LayoutInflater`把处理`fragment`的事情最终交给了`FragmentManagerImpl`。
145 |
146 | 而对于`FragmentManagerImpl`的分析其实已经超过了本文的界限。
147 |
148 | 但是我想再深入,看看`Fragment`的`onCreateView`方法究竟是什么时候调用的!!
149 |
150 | 所以继续跟下去:
151 |
152 | ```
153 | public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
154 | //mFragmentManager 是 FragmentManagerImpl 的实例
155 | return mHost.mFragmentManager.onCreateView(parent, name, context, attrs);
156 | }
157 |
158 | // #FragmentManagerImpl
159 | @Override
160 | public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
161 | // 不为 fragment 直接 return null 说明确实只处理 fragment
162 | if (!"fragment".equals(name)) {
163 | return null;
164 | }
165 | // xml 中的 各种 属性 fname为 Fragemnt 的全路径
166 | String fname = attrs.getAttributeValue(null, "class");
167 | TypedArray a = context.obtainStyledAttributes(attrs, FragmentTag.Fragment);
168 | if (fname == null) {
169 | fname = a.getString(FragmentTag.Fragment_name);
170 | }
171 | int id = a.getResourceId(FragmentTag.Fragment_id, View.NO_ID);
172 | String tag = a.getString(FragmentTag.Fragment_tag);
173 | a.recycle();
174 |
175 | if (!Fragment.isSupportFragmentClass(mHost.getContext(), fname)) {
176 | // Invalid support lib fragment; let the device's framework handle it.
177 | // This will allow android.app.Fragments to do the right thing.
178 | return null;
179 | }
180 | // 如果配置的信息不够 则会抛异常
181 | int containerId = parent != null ? parent.getId() : 0;
182 | if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
183 | throw new IllegalArgumentException(attrs.getPositionDescription()
184 | + ": Must specify unique android:id, android:tag, or have a parent with an id for " + fname);
185 | }
186 |
187 | // If we restored from a previous state, we may already have
188 | // instantiated this fragment from the state and should use
189 | // that instance instead of making a new one.
190 | // 尝试着先去找 fragment
191 | Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;
192 | if (fragment == null && tag != null) {
193 | fragment = findFragmentByTag(tag);
194 | }
195 | if (fragment == null && containerId != View.NO_ID) {
196 | fragment = findFragmentById(containerId);
197 | }
198 |
199 | if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"
200 | + Integer.toHexString(id) + " fname=" + fname
201 | + " existing=" + fragment);
202 | // 如果没有 则去实例化
203 | if (fragment == null) {
204 | // 调用 instantiate 其实也是反射来实例化的。
205 | fragment = Fragment.instantiate(context, fname);
206 | fragment.mFromLayout = true;
207 | fragment.mFragmentId = id != 0 ? id : containerId;
208 | fragment.mContainerId = containerId;
209 | fragment.mTag = tag;
210 | fragment.mInLayout = true;
211 | fragment.mFragmentManager = this;
212 | fragment.mHost = mHost;
213 | fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
214 | addFragment(fragment, true);
215 |
216 | } else if (fragment.mInLayout) {
217 | // A fragment already exists and it is not one we restored from
218 | // previous state.
219 | throw new IllegalArgumentException(attrs.getPositionDescription()
220 | + ": Duplicate id 0x" + Integer.toHexString(id)
221 | + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)
222 | + " with another fragment for " + fname);
223 | } else {
224 | // This fragment was retained from a previous instance; get it
225 | // going now.
226 | fragment.mInLayout = true;
227 | fragment.mHost = mHost;
228 | // If this fragment is newly instantiated (either right now, or
229 | // from last saved state), then give it the attributes to
230 | // initialize itself.
231 | if (!fragment.mRetaining) {
232 | fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
233 | }
234 | }
235 |
236 | // If we haven't finished entering the CREATED state ourselves yet,
237 | // push the inflated child fragment along.
238 | if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
239 | moveToState(fragment, Fragment.CREATED, 0, 0, false);
240 | } else {
241 | moveToState(fragment);
242 | }
243 |
244 | if (fragment.mView == null) {
245 | throw new IllegalStateException("Fragment " + fname
246 | + " did not create a view.");
247 | }
248 | if (id != 0) {
249 | fragment.mView.setId(id);
250 | }
251 | if (fragment.mView.getTag() == null) {
252 | fragment.mView.setTag(tag);
253 | }
254 | return fragment.mView;
255 | }
256 | ```
257 |
258 | 可以看到,在处理 xml 中的属性后,会先去寻找要加载的 fragment 是否已经加载过了,如果没有则会调用`fragment = Fragment.instantiate(context, fname);`,这个方法也是
259 | 反射,这点其实跟 View 的处理是一样的。
260 |
261 | 接着会去调用`moveToState`方法,而这个方法里,我看了`onCreateView`方法的调用时机。
262 |
263 | 伪代码如下(太复杂,删减了绝大部分代码):
264 |
265 | ```
266 | // # FragmentManager
267 | void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {
268 | //...
269 | f.mView = f.performCreateView(xxx);
270 | //....
271 | }
272 | // 真正的调用时机在这里!!
273 | // # Fragment
274 | View performCreateView(LayoutInflater inflater, ViewGroup container,
275 | Bundle savedInstanceState) {
276 | if (mChildFragmentManager != null) {
277 | mChildFragmentManager.noteStateNotSaved();
278 | }
279 | // 调用onCreateView 熟悉吧?
280 | return onCreateView(inflater, container, savedInstanceState);
281 | }
282 | ```
283 |
284 | 可以看到,`FragmentManager`的`moveToState`中会去调用`Fragment`的`performCreateView`方法,而它里面,调用了`onCreateView`!!
285 |
286 | `onCreateView`熟悉吧?就是我们使用 `Fragment` 第一个重写的方法!
287 |
288 | 终于找到啦!!
289 |
290 | 呼,藏得真深。
291 |
292 | 不过功夫不负有心人!~~~
293 |
294 | 爽!~
295 |
296 | ## 小结
297 |
298 | `FragmentActivity`通过 `setFactory`把对`fragment`标签的处理委托给了 `FragmentManageImpl`的`onCreateView`方法。
299 |
300 | 最终通过反射,实例化指定的 `Fragment`,并调用了`Fragment.performCreateView`,最后到我们所熟悉的`onCreateView`。
301 |
302 | 整体的流程分析完毕。
303 |
304 | 另外要说的是,`LayoutInflater.Factory`的作用其实非常强大,我们可以 Hook 每个 View 的创建于设置,比如 `AppCompact`库通过`AppCompactViewInflater` Hook 了大部分 View,给我们提供了向下兼容的功能;
305 |
306 | 另外它也还可以配合 DayNight 实现夜间模式功能,有兴趣可以去看看`AppCompactActivity`、`AppCompactViewInflater`等类,有机会再讲吧。
307 |
308 | 到此对于 LayoutInflater 的源码分析已经结束,在查看源码的过程中发现一枚彩蛋,有兴趣的可以继续阅读:[LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
309 |
310 |
311 |
--------------------------------------------------------------------------------
/LayoutInflater.md:
--------------------------------------------------------------------------------
1 | # LayoutInflater 源码分析(一)之 inflate 深度分析
2 |
3 |
4 | [LayoutInflater 源码分析(一)之 inflate 深度分析](./LayoutInflater.md)
5 | [LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
6 | [LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
7 | [LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
8 |
9 |
10 | ## 简介
11 |
12 | public abstract class LayoutInflater
13 |
14 |
15 | `LayoutInflater`,从名字就可以看出它用于加载布局。
16 |
17 |
18 | 我们常用的方式大概如下:
19 |
20 | ```
21 | // 方法定义:inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
22 | View view = LayoutInflater.from(context).inflate(R.layout.resource,root,flase);
23 | ```
24 |
25 | PS:`LayoutInflater`的获取方式还有很多种,实际最终调用的是 Context.getSystemService 方法,关于getSystemService 的分析,有兴趣的可以看看[Context.getSystemService分析](context-getsystemservice.md)。
26 |
27 |
28 | 上述代码我写过无数遍,但是心中一直有很多疑问:
29 |
30 | - 上述方法中的`root`、`attachToRoot`究竟有什么作用?
31 | - 它究竟是在哪里实例化View又是如何去实例化 View 的?
32 | - 为什么系统的View我们在Xml里不需要写全路径,而自定义View却需要?
33 | - 它又是如何处理`fragment`以及各种标签如`include`、`merge`的?
34 | - `View`的`onFinishInflate`是否跟它有关呢?
35 |
36 | 这一切都藏在源码里,所以深入源码一点点了解吧!
37 |
38 | ## inflate深入解析
39 |
40 | 上面的例子中可以看到,我们调用的是`inflate(in resource, in root, in attachToRoot)`方法,所以首先分析一下该方法。
41 |
42 | ```
43 | public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
44 | //获取rescources
45 | final Resources res = getContext().getResources();
46 | if (DEBUG) {
47 | Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
48 | + Integer.toHexString(resource) + ")");
49 | }
50 | // 获取parser 这里我不关心parse是怎么来的
51 | final XmlResourceParser parser = res.getLayout(resource);
52 | try {
53 | // 调用了另外一个inflate方法
54 | return inflate(parser, root, attachToRoot);
55 | } finally {
56 | parser.close();
57 | }
58 | }
59 | ```
60 |
61 | 上面代码可以看到该方法主要是获取一个`XmlResourceParser`对象parser(这里不关心它是如何来的)。
62 |
63 | 不过需要提一下的这里解析XML采用的是 **Pull**方法(不知道的自行Google)。
64 |
65 | 然后调用了另外一个`inflate`方法,所以我们还需要继续跟踪`inflate(parser, root, attachToRoot)`才能进一步理解。
66 |
67 | 上代码!
68 |
69 | ```
70 | public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
71 | synchronized (mConstructorArgs) {
72 | Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
73 | // 一些赋值 后续会有用到
74 | final Context inflaterContext = mContext;
75 | final AttributeSet attrs = Xml.asAttributeSet(parser);
76 | Context lastContext = (Context) mConstructorArgs[0];
77 | mConstructorArgs[0] = inflaterContext;
78 | // 先把result赋值为我们传递的root
79 | View result = root;
80 |
81 | try {
82 | // Look for the root node.
83 | int type;
84 | while ((type = parser.next()) != XmlPullParser.START_TAG &&
85 | type != XmlPullParser.END_DOCUMENT) {
86 | // Empty
87 | }
88 |
89 | if (type != XmlPullParser.START_TAG) {
90 | throw new InflateException(parser.getPositionDescription()
91 | + ": No start tag found!");
92 | }
93 | // 获取标签名字 比如FrameLayout
94 | final String name = parser.getName();
95 |
96 | if (DEBUG) {
97 | System.out.println("**************************");
98 | System.out.println("Creating root view: "
99 | + name);
100 | System.out.println("**************************");
101 | }
102 | // 这里的 TAG_MERGE 为 merge 看到了merge的身影
103 | if (TAG_MERGE.equals(name)) {
104 | // 不知道merge怎么用? 这个异常教你做人。
105 | if (root == null || !attachToRoot) {
106 | throw new InflateException(" can be used only with a valid "
107 | + "ViewGroup root and attachToRoot=true");
108 | }
109 | //如果为 merge 调用rInflate方法 后面再具体分析merge的情况
110 | rInflate(parser, root, inflaterContext, attrs, false);
111 | } else {
112 | // Temp is the root view that was found in the xml
113 | // 这里调用了一个createViewFromTag 从名字来看,就是用来创建View的!
114 | // 注意,这里的temp其实是我们xml里的top view,具体暂时先不管 先把整个流程看了
115 | final View temp = createViewFromTag(root, name, inflaterContext, attrs);
116 | //接下去处理LayoutParams
117 | ViewGroup.LayoutParams params = null;
118 | //如果我们传递进来的root不为null
119 | if (root != null) {
120 | if (DEBUG) {
121 | System.out.println("Creating params from root: " +
122 | root);
123 | }
124 | // Create layout params that match root, if supplied
125 | // 那么调用 root的generateLayoutParams 来生成LayoutParamas
126 | params = root.generateLayoutParams(attrs);
127 | //如果attachToRoot为false,那么就把刚生成的params赋值给View
128 | if (!attachToRoot) {
129 | // Set the layout params for temp if we are not
130 | // attaching. (If we are, we use addView, below)
131 | temp.setLayoutParams(params);
132 | }
133 | }
134 |
135 | if (DEBUG) {
136 | System.out.println("-----> start inflating children");
137 | }
138 | // 源码的打印日志已经告诉我,这里是加载子View的~~ 后续再讲解
139 | // Inflate all children under temp against its context.
140 | rInflateChildren(parser, temp, attrs, true);
141 |
142 | if (DEBUG) {
143 | System.out.println("-----> done inflating children");
144 | }
145 |
146 | // We are supposed to attach all the views we found (int temp)
147 | // to root. Do that now.
148 | // root不为null 并且 attachToRoot 则直接把temp添加到root里去
149 | if (root != null && attachToRoot) {
150 | root.addView(temp, params);
151 | }
152 |
153 | // Decide whether to return the root that was passed in or the
154 | // top view found in xml.
155 | // null或false 那么结果就是之前的top view了
156 | if (root == null || !attachToRoot) {
157 | result = temp;
158 | }
159 | }
160 |
161 | } catch (XmlPullParserException e) {
162 | InflateException ex = new InflateException(e.getMessage());
163 | ex.initCause(e);
164 | throw ex;
165 | } catch (Exception e) {
166 | InflateException ex = new InflateException(
167 | parser.getPositionDescription()
168 | + ": " + e.getMessage());
169 | ex.initCause(e);
170 | throw ex;
171 | } finally {
172 | // Don't retain static reference on context.
173 | mConstructorArgs[0] = lastContext;
174 | mConstructorArgs[1] = null;
175 | }
176 |
177 | Trace.traceEnd(Trace.TRACE_TAG_VIEW);
178 | // 返回结果
179 | return result;
180 | }
181 | }
182 | ```
183 |
184 | 可以看到该方法是重点了。
185 |
186 | 这里出现了`merge`的踪迹,可以看到遇到`merge`标签,**当root为null或者attachToRoot为false的时候,直接抛了异常!**
187 | 也可以看到如果是`merge`标签,走的是`rInflate`方法(不过这里暂时不分析`rInflate`方法)。
188 |
189 |
190 | 关键的是,我看到`inflate`方法处理了`root`与`attachToRoot`参数。
191 |
192 | 围绕`root`是否为`null`有两种处理分支:
193 |
194 | 第一种 当`root`不为`null`的时候:
195 |
196 | 1. 调用`root.generateLayoutParams`方法来生成`LayoutParamas`并赋值给`paramas`
197 | 2. 然后如果`attachToRoot`为`false`,则把`paramas`赋值给`createViewFromTag`解析出来的`temp`(XML里的根布局)
198 | 3. 而如果`attachToRoot`为`true`的话,则会 调用`root.addView(temp, params);` **直接把`temp`给加到`root`里去**。如果我们自己再调用`addView`则会报错!
199 |
200 |
201 | 这里再提一下`root` 对`topView`的`LayoutParamas`的影响:
202 |
203 | 需要先提一下 LayoutParamas 一般有3种来源:
204 |
205 | 1. 用户完全自定义 自己 `new` 出来
206 | 2. ViewGroup.generateLayoutParams 方法生成 上面已经提到
207 | 3. ViewGroup.generateDefaultLayoutParams 方法生成,在`addView`的时候 如果 `childView` 没有 LayoutParams 属性的话,会由这个方法生成。
208 |
209 | 来看一下 addView 里对 paramas 的操作就明白了:
210 |
211 | ```
212 | public void addView(View child) {
213 | addView(child, -1);
214 | }
215 | public void addView(View child, int index) {
216 | if (child == null) {
217 | throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
218 | }
219 | LayoutParams params = child.getLayoutParams();
220 | if (params == null) {
221 | // 没有 params 则调用 generateDefaultLayoutParams 去生成
222 | params = generateDefaultLayoutParams();
223 | if (params == null) {
224 | throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
225 | }
226 | }
227 | addView(child, index, params);
228 | }
229 | ```
230 |
231 | 所以当 root 不为 null 的时候,topview 的 paramas 是通过`generateLayoutParams`生成的。
232 |
233 | 需要注意的是:`generateLayoutParams`与`generateDefaultLayoutParams`生成的 paramas 是不同的,前者需要传入子被添加的`View`的`AttributeSet`类型的`attrs`属性(也就是xml里配置的属性)作为参数来创建`LayoutParams`,而后者则无需传参,会无视我们在 xml 里配置的属性,所以它会影响到布局效果。
234 |
235 |
236 | 第二种 当`root`为`null`的时候:
237 |
238 | 是`null`的时候会返回`temp` (XML里的根布局)
239 |
240 | ```
241 | // null 或是 false 那么result=temp
242 | if (root == null || !attachToRoot) {
243 | result = temp;
244 | }
245 | ```
246 |
247 | 也可以看到,`root==null`如果成立,那么`attachToRoot`也就没有用了。
248 |
249 | 所以`attachToRoot`只有在`root`不为 null 的时候才有效。
250 |
251 | 大致总结成流程图如下所示:
252 |
253 | 
254 |
255 |
256 | 搞清楚`root`以及`attachToRoot`参数的影响之后,来看View究竟是如何被创建的。
257 |
258 | 进入`createViewFromTag`方法。
259 |
260 | ## createViewFromTag 解析
261 |
262 | 上面提到的`createViewFromTag`方法如下:
263 |
264 | ```
265 | /**
266 | * 提到了include,除了include,都会被使用
267 | * Convenience method for calling through to the five-arg createViewFromTag
268 | * method. This method passes {@code false} for the {@code ignoreThemeAttr}
269 | * argument and should be used for everything except {@code >include>}
270 | * tag parsing.
271 | */
272 | private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
273 | return createViewFromTag(parent, name, context, attrs, false);//这里传了false进去
274 | }
275 | ```
276 |
277 | 可以看到,它又调用了另外一个重载函数,并从注释中我们可以看到了`include`的信息。
278 |
279 | 该方法把`ignoreThemeAttr`属性赋值为了`false`,继续跟下去。
280 |
281 | ```
282 | /**
283 | * Creates a view from a tag name using the supplied attribute set.
284 | * @param ignoreThemeAttr {@code true} to ignore the {@code android:theme}
285 | * attribute (if set) for the view being inflated,
286 | * {@code false} otherwise
287 | */
288 | View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
289 | boolean ignoreThemeAttr) {
290 | if (name.equals("view")) {
291 | name = attrs.getAttributeValue(null, "class");
292 | }
293 |
294 | // Apply a theme wrapper, if allowed and one is specified.
295 | // 之前传递过来的为false
296 | if (!ignoreThemeAttr) {
297 | final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
298 | final int themeResId = ta.getResourceId(0, 0);
299 | //如果设置了theme 那么context会被重新实例化为 ContextThemeWrapper
300 | if (themeResId != 0) {
301 | context = new ContextThemeWrapper(context, themeResId);
302 | }
303 | ta.recycle();
304 | }
305 | // 彩蛋后续 分析
306 | if (name.equals(TAG_1995)) {
307 | // Let's party like it's 1995!
308 | return new BlinkLayout(context, attrs);
309 | }
310 | // 这里开始去创建View了
311 | try {
312 | View view;
313 | //如果mFactory2不为null 那么mFactory2先解析
314 | if (mFactory2 != null) {
315 | view = mFactory2.onCreateView(parent, name, context, attrs);
316 | } else if (mFactory != null) {
317 | // 接着是 mFactory
318 | view = mFactory.onCreateView(name, context, attrs);
319 | } else {
320 | view = null;
321 | }
322 | // 如果 mFactory2 mFactory都返回null了 那么如果mPrivateFactory不为null,则交给它
323 | if (view == null && mPrivateFactory != null) {
324 | view = mPrivateFactory.onCreateView(parent, name, context, attrs);
325 | }
326 | // 如果 那几个factory都返回null 即view还是null 那么继续
327 | if (view == null) {
328 | final Object lastContext = mConstructorArgs[0];
329 | mConstructorArgs[0] = context;
330 | try {
331 | // 有. 代表不是系统自带的View,比如TextView、me.yifeiyuan.XXXLayout
332 | if (-1 == name.indexOf('.')) {
333 | view = onCreateView(parent, name, attrs);
334 | } else {
335 | // 系统自带的View
336 | view = createView(name, null, attrs);
337 | }
338 | } finally {
339 | mConstructorArgs[0] = lastContext;
340 | }
341 | }
342 |
343 | return view;
344 | } catch (InflateException e) {
345 | throw e;
346 |
347 | } catch (ClassNotFoundException e) {
348 | final InflateException ie = new InflateException(attrs.getPositionDescription()
349 | + ": Error inflating class " + name);
350 | ie.initCause(e);
351 | throw ie;
352 |
353 | } catch (Exception e) {
354 | final InflateException ie = new InflateException(attrs.getPositionDescription()
355 | + ": Error inflating class " + name);
356 | ie.initCause(e);
357 | throw ie;
358 | }
359 | }
360 | ```
361 |
362 | 该`createViewFromTag`方法 先处理了主题属性,再走入创建View的流程。
363 |
364 | 这里还涉及到了几个Factory,这其实是系统留给我们的Hook入口,我们可以人为的干涉系统创建View,可以添加更多功能,比如夜间模式。
365 |
366 | `Factory`相关的知识后续再讲。
367 |
368 | 另外,我们可以看到该方法依然没有涉及到创建View的具体实现,而是又会去调用`onCreateView`以及`createView`方法,这俩方法总应该是View创建的具体地方了吧?!!
369 |
370 | ## onCreateView 与 createView
371 |
372 | 初步来看`createView`方法负责创建自定义View,而`onCreateView`方法负责创建系统自带的View。
373 | 但是感觉比较奇怪,因为不管是什么View,创建的套路应该是一样才对啊~
374 | 感觉有诈!
375 |
376 | ```
377 | protected View onCreateView(String name, AttributeSet attrs)
378 | throws ClassNotFoundException {
379 | return createView(name, "android.view.", attrs);
380 | }
381 | ```
382 |
383 | 咦!~ `onCreateView`调用了`createView`,到最后,其实都是调用`createView`方法啦!
384 |
385 | 另外还传入了`android.view.`的一个参数,咦?这不是系统自带的View的包路径吗?
386 |
387 | 继续深入`createView`。
388 |
389 | ```
390 | public final View createView(String name, String prefix, AttributeSet attrs)
391 | throws ClassNotFoundException, InflateException {
392 | // 构造方法缓存
393 | Constructor extends View> constructor = sConstructorMap.get(name);
394 | Class extends View> clazz = null;
395 |
396 | try {
397 | // Trace
398 | Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
399 | //没有缓存 则去获取constructor 并存入缓存 注意这个缓存是静态的
400 | if (constructor == null) {
401 | // Class not found in the cache, see if it's real, and try to add it
402 | // 注意 注意 注意 在这里把 View的全称拼全,并loadClass 难怪要传递android.View.进来啊~
403 | clazz = mContext.getClassLoader().loadClass(
404 | prefix != null ? (prefix + name) : name).asSubclass(View.class);
405 | // 让 Filter 处理这个clazz能否被加载
406 | if (mFilter != null && clazz != null) {
407 | boolean allowed = mFilter.onLoadClass(clazz);
408 | if (!allowed) {
409 | // 如果不允许加载 则failNotAllowed会抛出异常!
410 | failNotAllowed(name, prefix, attrs);
411 | }
412 | }
413 | // 反射获取构造方法 并存入缓存
414 | constructor = clazz.getConstructor(mConstructorSignature);
415 | constructor.setAccessible(true);
416 | sConstructorMap.put(name, constructor);
417 | } else {
418 | // 如果有缓存 就走filter流程,并把结果存入缓存(非静态)
419 | // If we have a filter, apply it to cached constructor
420 | if (mFilter != null) {
421 | // Have we seen this name before?
422 | Boolean allowedState = mFilterMap.get(name);
423 | if (allowedState == null) {
424 | // New class -- remember whether it is allowed
425 | clazz = mContext.getClassLoader().loadClass(
426 | prefix != null ? (prefix + name) : name).asSubclass(View.class);
427 | // 获取allowed 并存入 缓存
428 | boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
429 | mFilterMap.put(name, allowed);
430 | if (!allowed) {
431 | failNotAllowed(name, prefix, attrs);
432 | }
433 | } else if (allowedState.equals(Boolean.FALSE)) {
434 | failNotAllowed(name, prefix, attrs);
435 | }
436 | }
437 | }
438 | // mConstructorArgs存放了context 跟 args
439 | Object[] args = mConstructorArgs;
440 | args[1] = attrs;
441 | // 终于看到view实例化的地方了!!
442 | final View view = constructor.newInstance(args);
443 | // 如果是ViewStub 则设置LayoutInflater给它用
444 | if (view instanceof ViewStub) {
445 | // Use the same context when inflating ViewStub later.
446 | final ViewStub viewStub = (ViewStub) view;
447 | viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
448 | }
449 | return view;
450 |
451 | } catch (NoSuchMethodException e) {
452 | InflateException ie = new InflateException(attrs.getPositionDescription()
453 | + ": Error inflating class "
454 | + (prefix != null ? (prefix + name) : name));
455 | ie.initCause(e);
456 | throw ie;
457 |
458 | } catch (ClassCastException e) {
459 | // If loaded class is not a View subclass
460 | InflateException ie = new InflateException(attrs.getPositionDescription()
461 | + ": Class is not a View "
462 | + (prefix != null ? (prefix + name) : name));
463 | ie.initCause(e);
464 | throw ie;
465 | } catch (ClassNotFoundException e) {
466 | // If loadClass fails, we should propagate the exception.
467 | throw e;
468 | } catch (Exception e) {
469 | InflateException ie = new InflateException(attrs.getPositionDescription()
470 | + ": Error inflating class "
471 | + (clazz == null ? "" : clazz.getName()));
472 | ie.initCause(e);
473 | throw ie;
474 | } finally {
475 | Trace.traceEnd(Trace.TRACE_TAG_VIEW);
476 | }
477 | }
478 | ```
479 |
480 | 调来调去,终于到真正实例化View的地方了。
481 |
482 | 看到这方法的 `clazz = mContext.getClassLoader().loadClass(prefix != null ? (prefix + name) : name).asSubclass(View.class)` 步骤会把系统自带的`View`的路径拼起来,把类加载进来;
483 |
484 | 然后`clazz.getConstructor(mConstructorSignature);`获取`View`的构造方法,最终通过反射`constructor.newInstance(args);`实例化View。
485 |
486 | 如果你足够机智,你会发现这里出来一个问题,WebView 怎么办?
487 |
488 | 它的路径可是`android.webkit`啊~
489 | 其实这里涉及到 LayoutInflater 的一个子类`com.android.internal.policy.PhoneLayoutInflater`,它处理了`android.widget.`、`android.webkit.`、`android.app.`这些路径。
490 |
491 | **事实上,我们最开始使用`LayoutInflater.from(cxt)`获取的就是`PhoneLayoutInflater`的实例。**
492 |
493 | 另外这里又涉及到一个Hook入口,即`Filter`,但是我不知道它的使用场景。
494 |
495 | `createView`方法里解答了我 *View是哪里实例化的*以及*XML中系统View为什么不需要写全路径* 这两个疑问。
496 |
497 | ## 小结
498 |
499 | 这一篇中分析了如下方法(省去了参数):
500 |
501 | - `inflate`:LayoutInflater对外开放的入口,这里分析了 root与attachToRoot 参数的作用。
502 | - `createViewFromTag`:处理主题属性与Factory的Hook
503 | - `onCreateView`: 处理系统自带View的路径,`android.view.`,实际调用的还是`createView`方法
504 | - `createView`: 真正实例化View的地方,通过View的路径去加载类并获取构造方法,通过反射获取View的实例。
505 |
506 | 本篇解决了一些疑问:
507 |
508 | - 上述方法中的`root`、`attachToRoot`究竟有什么作用?
509 | - 影响了`merge`标签,
510 | - View是否直接被 add 到 root
511 | - View 的 LayoutParams 从何而来
512 | - inflate 方法的返回值
513 | - 为什么系统的View我们在Xml里不需要写全路径,而自定义View却需要?
514 | - 针对系统 View,会帮忙拼全路径,所以不需要写全
515 | - 它究竟是在哪里实例化View又是如何实例化 View 的?
516 | - 在 createView 方法中,默认利用反射实例化 View
517 | - 也可通过 Factory hook 的方式实例化
518 |
519 | 但是还有好多疑问没有解决,也还有部分重要的方法没有解析,所以需要继续探索。
520 |
521 | 篇幅太长了,所以先小结一下,换一篇继续。
522 |
523 | 下一篇着重分析`merge`、`include`等标签是如何处理的。
524 |
525 | 已经写好啦:[LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
526 |
527 |
528 |
529 |
530 |
--------------------------------------------------------------------------------
/Learned.md:
--------------------------------------------------------------------------------
1 | # 心得
2 |
3 | 看源码的心得。
4 |
5 |
6 |
7 | ## 命名
8 |
9 |
10 | XXXXXNative ,都是 Binder 对象,它们相当于AIDL默认生成的代码中的 Stub 类:
11 |
12 | 比如 ActivityManagerNative ,ApplicationThreadNative
13 |
14 |
15 | XXXRecord 类通常是保存 XXX的信息的:
16 |
17 | 比如 ProcessRecord 是用来保存进程信息的;
18 |
19 | ActivityRecord 是用来保存 Activity 信息的。
20 |
--------------------------------------------------------------------------------
/ProcessRecord.md:
--------------------------------------------------------------------------------
1 | # ProcessRecord
2 |
3 |
4 | Full information about a particular process that is currently running.
5 |
6 |
7 | 保存进程的信息。
8 |
9 |
10 | 修改进程的 adj
11 |
12 |
13 | ```
14 | int modifyRawOomAdj(int adj) {
15 | if (hasAboveClient) {
16 | // If this process has bound to any services with BIND_ABOVE_CLIENT,
17 | // then we need to drop its adjustment to be lower than the service's
18 | // in order to honor the request. We want to drop it by one adjustment
19 | // level... but there is special meaning applied to various levels so
20 | // we will skip some of them.
21 | if (adj < ProcessList.FOREGROUND_APP_ADJ) {
22 | // System process will not get dropped, ever
23 | } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
24 | adj = ProcessList.VISIBLE_APP_ADJ;
25 | } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
26 | adj = ProcessList.PERCEPTIBLE_APP_ADJ;
27 | } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
28 | adj = ProcessList.CACHED_APP_MIN_ADJ;
29 | } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
30 | adj++;
31 | }
32 | }
33 | return adj;
34 | }
35 | ```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RTFSC
2 |
3 | > Read The Fucking Source Code
4 |
5 | ## 初衷&为什么要阅读源码
6 |
7 | 随着做Android开发时间越来越久,看别人的文章博客对自己的收益越来越少,以前看10篇文章,可能9篇对自己有用,后来慢慢减少,8 7 6..1 。
8 |
9 | 再加上现在国内的风气不好,标题党特别多,质量好的文章太少,在茫茫文章中获取有用信息变得越来越困难。
10 |
11 | 投入与回报不成比例,所以需要换一种方式去学习。
12 |
13 | 现在我更推荐看书以及阅读源码。
14 |
15 | 相对于看文章,看书有利于系统的学习,看源码的好处更是多多。
16 |
17 | 书也是有好有坏,关于书籍,我有一个记录读书笔记的项目[ReadingNotes](https://github.com/AlanCheen/ReadingNotes),记录读书笔记,也有些扩展,对书籍也有一个相对比较客观的评价,或许可以帮到你,这里就不多说了。
18 |
19 | ## 阅读源码的好处
20 |
21 | 『所有的知识其实都来自源码』是我最深的感悟。
22 |
23 | 通过阅读源码,对知识点的掌握不再流于表面,而能够做到知其然以及所以然,极大地提升判断力,不再人云亦云。
24 |
25 | 阅读源码还能极大的扩大知识面,通常在阅读源码的时候你会发现很多你根本不知道,或者看文章博客根本不会获取得到的知识,经常会遇到各种『彩蛋』。
26 |
27 | Android 源码是学习设计模式的最佳途径之一,Android 团队遇到的坑,比我写过的代码还多,Android 源码中到处可见设计模式的影子,阅读它,可以加深对设计模式的理解。
28 |
29 | 好处绝不止我所说的,自己去体会。
30 |
31 | ## 哪里可以看Android源码
32 |
33 | Android 源码的查看一般有以下几种方式:
34 |
35 | - 在在线网站上查看,如:[grepcode](http://grepcode.com/),[androidxref](http://androidxref.com/)
36 | - 获取Android Framework源码查看,clone [frameworks_base](https://github.com/android/platform_frameworks_base) ,在 Mac 端可以使用 Sublime 配合 CTAG 查看。
37 | - 使用 AndroidStudio 看
38 |
39 | 取合适自己的。
40 |
41 | ## 阅读源码的姿势
42 |
43 | 源码数量庞大,如果漫无目的地去阅读很容易迷失自己,所以阅读源码要有一定的技巧。
44 |
45 | - 要有明确的目标,带着问题阅读源码
46 | - 由浅入深,一步一步来
47 |
48 | 比如针对某一个问题去查看源码,eg. `invalidate` 和 `postInvalidate` 的关系与区别是什么?
49 | 这样有目标性的去寻找答案,才不容易迷失。
50 |
51 | 另外阅读源码不是容易的事情,可以从简单的类开始阅读,培养阅读习惯以及技巧,增加信心,再一层一层深入,不宜在刚开始就非常深入,这样容易打击自信,甚至开始『怀疑猿生』。
52 |
53 | ## 资料
54 |
55 | 另外这些资料可能对你有帮助:
56 |
57 | - [大牛们是怎么阅读 Android 系统源码的?](https://www.zhihu.com/question/19759722)
58 | - [阅读 ANDROID 源码的一些姿势](http://kaedea.com/2016/02/09/android-about-source-code-how-to-read/)
59 |
60 | ## 加入我们
61 |
62 | 最初,其实我是想一个人默默的啃源码,不过后来有人想要加入,所以现在开放加入。
63 |
64 | 如果你有兴趣加入,请先看看条件。
65 |
66 | 0. 绝对不能是伸手党
67 | 1. 有上进心,认真,爱学习
68 | 2. 最好有写博客文章的习惯
69 | 3. 有爱心,愿意互相帮助
70 | 4. 严肃认真对待此事
71 |
72 | 如果你觉得你差不多符合条件,并且有兴趣加入,那么看下去吧。
73 |
74 | 1. 加入 Github 组织,提 issue 留下意向,github 昵称或者邮件,以及博客地址,我看到验证后会发送邀请。
75 | 2. 加入 Tower,我正在使用 Tower 作为源码阅读的计划与管理工具,感觉挺不错的,也方便查看成员的计划与动态,有兴趣的点[邀请链接](https://tower.im/join?t=bc25cd4a8571075ba0edc9b50cb3ba39)。
76 | 3. 加我微信。
77 |
78 | 
79 |
80 | ## 捐助
81 |
82 | 如果来到这里,你有所收获,并且想要回馈的话,那么非常欢迎去[这里](http://yifeiyuan.me/donate/)捐助,记得留下名号,不盛感激。
83 |
84 | ## 版权信息
85 |
86 | 不欢迎并拒绝任何形式的全文转载!
87 |
88 | 其他还在考虑。
89 |
90 |
--------------------------------------------------------------------------------
/Space.md:
--------------------------------------------------------------------------------
1 | # Space 源码分析
2 |
3 |
4 | ## 简介
5 |
6 | public final class Space extends View
7 |
8 | Space是一个轻量的View,可以在布局中被用来创建间隙;常用于布局优化;
9 |
10 | 介于可能很多人根本不知道Space的存在!所以稍微提一下它的使用场景,比如以下场景的右侧小三角,就可以使用Space:
11 |
12 | 
13 |
14 | 在两个三角之间放置一个`Space`,两三角分别位于它的上下,控制它的高度就能控制三角之间的间隔。
15 |
16 | ```
17 |
23 |
24 |
32 |
33 |
39 |
40 |
48 |
49 | ```
50 |
51 |
52 | ## 构造方法分析
53 |
54 | 看第一个构造方法即可。
55 |
56 | ```
57 | // 最终都会调用这个构造方法
58 | public Space(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
59 | super(context, attrs, defStyleAttr, defStyleRes);
60 | // 如果是VISIBLE 则改为 INVISIBLE
61 | if (getVisibility() == VISIBLE) {
62 | setVisibility(INVISIBLE);
63 | }
64 | }
65 |
66 | public Space(Context context, AttributeSet attrs, int defStyleAttr) {
67 | this(context, attrs, defStyleAttr, 0);
68 | }
69 |
70 |
71 | public Space(Context context, AttributeSet attrs) {
72 | this(context, attrs, 0);
73 | }
74 |
75 | public Space(Context context) {
76 | //noinspection NullableProblems
77 | this(context, null);
78 | }
79 | ```
80 |
81 | 跟ViewStub类似,Space在构造方法里做了一些操作:**当可见性为VISIBLE的时候,把它改为INVISIBLE了**。
82 |
83 | 由于Space方法非常少,接下去直接都分析了。
84 |
85 | ## 其余方法分析
86 |
87 |
88 | ```
89 | /**
90 | * Draw nothing.
91 | *
92 | * @param canvas an unused parameter.
93 | */
94 | @Override
95 | public void draw(Canvas canvas) {
96 | //空方法
97 | }
98 |
99 | /**
100 | * Compare to: {@link View#getDefaultSize(int, int)}
101 | * If mode is AT_MOST, return the child size instead of the parent size
102 | * (unless it is too big).
103 | */
104 | private static int getDefaultSize2(int size, int measureSpec) {
105 | int result = size;
106 | int specMode = MeasureSpec.getMode(measureSpec);
107 | int specSize = MeasureSpec.getSize(measureSpec);
108 |
109 | switch (specMode) {
110 | case MeasureSpec.UNSPECIFIED:
111 | result = size;
112 | break;
113 | case MeasureSpec.AT_MOST: //wrap_content 返回更小的值
114 | result = Math.min(size, specSize);
115 | break;
116 | case MeasureSpec.EXACTLY:
117 | result = specSize;
118 | break;
119 | }
120 | return result;
121 | }
122 |
123 | @Override
124 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
125 | // getSuggestedMinimumWidth() 根据minWidth以及背景的宽度来返回
126 | setMeasuredDimension(
127 | getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
128 | getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
129 | }
130 | ```
131 |
132 | Space跟ViewStub一个套路,`draw()`都为空方法,然后重写`onMeasure`,相比ViewStub,Space代码更加比较简单。
133 |
134 | 另外一般我们使用Space都是会指定宽高,大部分走的是 EXACTLY的流程。
135 |
136 | ## 要点
137 |
138 | 0. Space 用来做间隙非常有用
139 | 1. Space 默认为不可见(invisible),但是有宽高,会占据空间。
140 | 2. 布局文件中设置 VISIBLE 无效。
141 |
142 | ## 小结
143 |
144 | ViewStub跟Space作为Android布局优化的常用手段,有着一些同样的思路值得我们去学习:
145 |
146 | - 不绘制(减少overDraw)
147 | - 优化或者不参与测量与布局(提高整体布局的渲染速度)
148 |
149 |
150 | [ViewStub源码分析](./ViewStub.md)
151 |
152 | 2016年8月11日下午2:41
153 |
154 |
155 |
--------------------------------------------------------------------------------
/SystemServer.md:
--------------------------------------------------------------------------------
1 | # SystemServer
2 |
3 |
4 | com.android.server.SystemServer
5 |
6 | SystemServer 是什么?
7 |
8 |
9 | 系统服务,比如 ActivityManagerService ,PackageManagerService 都是在这里实例化的
10 |
11 |
12 |
13 |
14 |
15 | SystemServiceManager
--------------------------------------------------------------------------------
/ViewRootImpl.md:
--------------------------------------------------------------------------------
1 | # ViewRootImpl
2 |
3 | ## 简介
4 | /**
5 | * The top of a view hierarchy, implementing the needed protocol between View
6 | * and the WindowManager. This is for the most part an internal implementation
7 | * detail of {@link WindowManagerGlobal}.
8 | */
9 | public final class ViewRootImpl implements ViewParent,
10 | View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks
11 |
12 |
13 |
14 | ## ViewRootImpl 的创建时机
15 |
16 |
17 | //todo 详细的分析
18 |
19 |
20 | 大致流程记录如下
21 |
22 | ActivityThread.performLaunchActivity
23 | => activity.attach
24 | => ActivityThread.handleResumeActivity
25 | => WindowManager.addView
26 | => WindowManagerImpl.addView
27 | => WindowManagerGlobal.addView
28 | => root = new ViewRootImpl
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ViewStub.md:
--------------------------------------------------------------------------------
1 | # ViewStub 源码分析
2 |
3 |
4 | ## ViewStub简介
5 |
6 |
7 | public final class ViewStub extends View
8 |
9 | ViewStub 是一个宽高都为0,不可见的(GONE),不参与measure与layout(绝大部分情况),不绘制任何东西,可以用来做懒加载的View;常用于布局优化;
10 |
11 | PS: 为什么说绝大部分情况不参与测量与布局呢?因为大部分ViewGroup对于GONE的View,都不会让它参与测量与布局流程(自定义的就不一定了,另外可以看一下FrameLayout的源码)。
12 |
13 | 首先需要说的是,本文涉及到两个角色,一个是 ViewStub本身,另外一个是被用来做懒加载的View,是ViewStub的作用对象,称之为『StubbedView』(本文用此称呼来替代)。
14 |
15 |
16 | ## ViewStub的简单使用教程
17 |
18 | `ViewStub` 的使用非常非常简单,只需要两步~
19 |
20 | Step 1. 在XML里配置使用:
21 |
22 | ```
23 |
31 | ```
32 |
33 | Step 2. 调用ViewStub的`inflate`
34 |
35 | ```
36 | ViewStub stub = (ViewStub)findViewById(R.id.stub);
37 | View stubbedView = stub.inflate();//后面分析
38 | //...初始化StubbedView
39 | ```
40 |
41 | 非常简单的两步,就能做到View的懒加载,非常方便,其原因是什么呢?
42 |
43 | 接下去深入源码分析一下。
44 |
45 | ## 构造方法分析
46 |
47 | 首先分析一下构造方法,了解一下它是如何创建的。
48 |
49 | ```
50 | public ViewStub(Context context, @LayoutRes int layoutResource) {
51 | this(context, null);
52 | // StubbedView的资源id
53 | mLayoutResource = layoutResource;
54 | }
55 |
56 | public ViewStub(Context context, AttributeSet attrs) {
57 | this(context, attrs, 0);
58 | }
59 |
60 | public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) {
61 | this(context, attrs, defStyleAttr, 0);
62 | }
63 |
64 | public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
65 | super(context);
66 |
67 | final TypedArray a = context.obtainStyledAttributes(attrs,
68 | R.styleable.ViewStub, defStyleAttr, defStyleRes);
69 | // mInflatedId 存储StubbedView的id
70 | mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
71 | // mLayoutResource 为StubbedView的resourceId
72 | mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
73 | // viewStub 自己的id
74 | mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
75 | a.recycle();
76 | // 设置为不可见
77 | setVisibility(GONE);
78 | // 不绘制本身
79 | setWillNotDraw(true);
80 | }
81 | ```
82 |
83 | `ViewStub`在构造方法里不仅仅获取赋值属性,比较关键的是,还 默认将ViewStub自己设置为不可见(跳过onMeasure与onLayout),不绘制。
84 |
85 | 这里有一个要点:**在XML里配置ViewStub的可见性是没有用的**。
86 |
87 |
88 | ## 测量 与 绘制
89 |
90 | ```
91 | @Override
92 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
93 | // 写死的宽高为0
94 | setMeasuredDimension(0, 0);
95 | }
96 |
97 | @Override
98 | public void draw(Canvas canvas) {
99 | //空方法,不draw任何东西
100 | }
101 |
102 | @Override
103 | protected void dispatchDraw(Canvas canvas) {
104 | //空方法,不draw任何东西
105 | }
106 | ```
107 |
108 | ## inflate()方法分析
109 |
110 | 之前在简单教程里有提到 `inflate`方法,它是`ViewStub`实现懒加载的最为关键的方法,接下去去分析一下。
111 |
112 |
113 | ```
114 | // 返回 StubbedView
115 | public View inflate() {
116 | // 尝试去获取 viewParent 第一次调用的时候不为null,而后则为null
117 | final ViewParent viewParent = getParent();
118 | // 当 viewParent 不为null的时候
119 | if (viewParent != null && viewParent instanceof ViewGroup) {
120 | // 我们在xml里配置的layout的资源id 如果id无效,则会报错
121 | if (mLayoutResource != 0) {
122 | final ViewGroup parent = (ViewGroup) viewParent;
123 | // 实例化 LayoutInflater
124 | final LayoutInflater factory;
125 | if (mInflater != null) {
126 | factory = mInflater;
127 | } else {
128 | factory = LayoutInflater.from(mContext);
129 | }
130 | // inflate,StubbedView在这里被实例化
131 | final View view = factory.inflate(mLayoutResource, parent,
132 | false);
133 | // 可以看到,这里如果我们在XML里写了inflateId,则会设置给StubbedView
134 | if (mInflatedId != NO_ID) {
135 | view.setId(mInflatedId);
136 | }
137 | // 注意:这两步步 ViewSutb 找到自己的位置,并从父View中移除了自己
138 | // 这会导致 以后调用inflate的时候 再也获取不到 viewParent了
139 | final int index = parent.indexOfChild(this);
140 | parent.removeViewInLayout(this);
141 | // 拿出ViewStub的LayoutParamas,不为null 则会赋值给 StubbedView
142 | final ViewGroup.LayoutParams layoutParams = getLayoutParams();
143 | // 把 StubbedView 添加到ViewStub的父View里
144 | if (layoutParams != null) {
145 | parent.addView(view, index, layoutParams);
146 | } else {
147 | parent.addView(view, index);
148 | }
149 | //使用一个弱引用来保存StubbedView
150 | mInflatedViewRef = new WeakReference(view);
151 | //回调listener
152 | if (mInflateListener != null) {
153 | mInflateListener.onInflate(this, view);
154 | }
155 | // 返回 StubbedView
156 | return view;
157 | } else {
158 | // id无效,则throw一个 IllegalArgumentException
159 | throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
160 | }
161 | } else {
162 | // inflate被调用一次后 就没有了ViewParent,就会报这个错
163 | throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
164 | }
165 | }
166 | ```
167 |
168 | 我在每行代码上都加上了详细的注释,主要的操作就是把StubbedView给Inflate出来,然后把它放到自己的位置,代码非常清晰,非常简单。
169 |
170 | 总结来说,其实`inflate`方法是做了一个『偷梁换柱』的操作,把 `StubbedView`动态的添加到自己原来的位置上,也因此实现了懒加载功能。
171 |
172 | 这里还需要注意的是 **ViewStub 必须要有一个 Parent,即必须要有父视图!**(谢谢 JangGwa 的提醒)
173 |
174 | 另外值得一提的是:ViewStub还重写了View的`setVisibility`方法,让我们来分析一下:
175 |
176 | ```
177 | public void setVisibility(int visibility) {
178 | // mInflatedViewRef 保存了 StubbedView还记得吗? inflate过后它就不是null了
179 | if (mInflatedViewRef != null) {
180 | View view = mInflatedViewRef.get();
181 | // 操作 StubbedView
182 | if (view != null) {
183 | view.setVisibility(visibility);
184 | } else {
185 | throw new IllegalStateException("setVisibility called on un-referenced view");
186 | }
187 | } else {
188 | // 操作ViewStub自己,构造方法里的GONE记得么?
189 | super.setVisibility(visibility);
190 | // 如果是 VISIBLE INVISIBLE 则会去调用 inflate方法!!!!
191 | if (visibility == VISIBLE || visibility == INVISIBLE) {
192 | inflate();//注意这一行代码
193 | }
194 | }
195 | }
196 | ```
197 |
198 | 可以看到`setVisibility`方法中也可能会调用`inflate()`方法,所以当我们想让StubbedView被加载进来,而我们不需要StubbedView的实例的时候,可以用`setVisibility(View.VISIBLE)`。
199 |
200 | 不过需要注意的是 不要再接着调用`inflate`方法!
201 |
202 |
203 | ## 要点
204 |
205 | 0. 使用ViewStub,必须指定layoutResourceId(必须是布局文件)
206 | 1. 在XML里配置ViewStub的可见性是没有用的
207 | 2. ViewStub 主要原理藏在`inflate()`方法中,是它把真正要加载的View给加载了进来
208 | 3. `inflate()`方法只能调用一次
209 | 4. ViewStub调用`inflate()`后就不要再用它了(让它功成身退!)
210 | 5. 要小心`setVisibility`方法,因为它可能会调用`inflate()`
211 | 6. 在XML里给ViewStub设置的LayoutParamas(宽高margin等)会传递给StubbedView,所以我们如果要控制StubbedView的LayoutParamas,则需要写在ViewStub里而不是StubbedView!
212 | 6. 期待补充!
213 |
214 | ## 小结
215 |
216 | 源码分析完毕,可以看到,ViewStub的源码还是非常简单的,但是作用还是挺大的。
217 |
218 | 最后编辑时间:2016.08.11
219 |
--------------------------------------------------------------------------------
/ZygoteInit.md:
--------------------------------------------------------------------------------
1 | # ZygoteInit
2 |
3 |
4 | com.android.internal.os.ZygoteInit
5 |
6 |
7 | Android 准备完 Native 环境后,在启动 zygote 进程过程中调用了 Java 世界的 ZygoteInit 的 main 方法,并且传入`com.anddroid.internal.os.ZygoteInit`和`true`两个参数。
8 |
9 |
10 |
11 |
12 |
13 | ```
14 | at android.os.Handler.handleCallback(Handler.java:733)
15 | at android.os.Handler.dispatchMessage(Handler.java:95)
16 | at android.os.Looper.loop(Looper.java:212)
17 | at android.app.ActivityThread.main(ActivityThread.java:5151)
18 | at java.lang.reflect.Method.invokeNative(Method.java)
19 | at java.lang.reflect.Method.invoke(Method.java:515)
20 | at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
21 | at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
22 | at dalvik.system.NativeStart.main(NativeStart.java)
23 | ```
24 |
25 |
26 | ```
27 | at android.app.Activity.performCreate(Activity.java:6049)
28 | at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
29 | at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2294)
30 | at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2403)
31 | at android.app.ActivityThread.access$800(ActivityThread.java:154)
32 | at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
33 | at android.os.Handler.dispatchMessage(Handler.java:102)
34 | at android.os.Looper.loop(Looper.java:135)
35 | at android.app.ActivityThread.main(ActivityThread.java:5298)
36 | at java.lang.reflect.Method.invoke(Native Method)
37 | at java.lang.reflect.Method.invoke(Method.java:372)
38 | at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:910)
39 | at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:705)
40 | ```
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/activity-setcontentview.md:
--------------------------------------------------------------------------------
1 | # Activity.setContentView 分析
2 |
3 | todo 尚未完成
4 |
5 | ## 引言
6 |
7 | 通常,我们在使用 Activity 的时候,都会在 onCreate 里调用setContentView这个方法,这样才能让我们的 UI 显示出来。
8 |
9 | 那么问题来了 setContentView 里做了什么呢?为什么这个方法叫 setContentView 呢?
10 |
11 | ## 探索 Activity.setContentView
12 |
13 | 看一下setContentView的实现(它有三个重载,代码差不多,就只列举一个最常用的):
14 |
15 | ```
16 | public void setContentView(@LayoutRes int layoutResID) {
17 | getWindow().setContentView(layoutResID);
18 | initWindowDecorActionBar();
19 | }
20 |
21 | public Window getWindow() {
22 | return mWindow;
23 | }
24 | ```
25 |
26 | 首先调用了 window 的 setContentView,接着调用 initWindowDecorActionBar,它是用来创建 ActionBar 的,这里就不多关心了。
27 |
28 | 接下去的关键是 mWindow 。
29 |
30 | mWindow 是什么,它又从何而来?
31 |
32 | 这要看一下 Activity.attach 方法了:
33 |
34 | NOTE:至于为什么是 attach,这涉及到 Activity 的启动过程,以后会讲,现在只要知道就好。
35 |
36 | ```
37 | //省略了很多参数
38 | //Activity
39 | final void attach(Context,ActivityThread,Instrumentation...){
40 | mWindow = new PhoneWindow(this);
41 | mWindow.setCallback(this);
42 | mWindow.getLayoutInflater().setPrivateFactory(this);
43 | }
44 | ```
45 |
46 | 偶,原来它是个 `com.android.internal.policy.PhoneWindow` 的实例。
47 |
48 | ## 揭秘 PhoneWindow.setContentView
49 |
50 | 看一下setContentView的实现。
51 |
52 | ```
53 | @Override
54 | public void setContentView(int layoutResID) {
55 | // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
56 | // decor, when theme attributes and the like are crystalized. Do not check the feature
57 | // before this happens.
58 | // mContentParent 是 contentView 的父容器
59 | if (mContentParent == null) {
60 | //第一次走这里肯定为 null 啦。
61 | installDecor();
62 | } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
63 | //第二次就先把所有 View 都移除
64 | mContentParent.removeAllViews();
65 | }
66 | // 处理 TRANSITIONS
67 | // 咱们按常规路走
68 | if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
69 | final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
70 | getContext());
71 | transitionTo(newScene);
72 | } else {
73 | // 填充 xml布局到mContentParent
74 | mLayoutInflater.inflate(layoutResID, mContentParent);
75 | }
76 | // 处理 Insets
77 | mContentParent.requestApplyInsets();
78 | // 回调 Activity.onContentChanged
79 | final Callback cb = getCallback();
80 | if (cb != null && !isDestroyed()) {
81 | cb.onContentChanged();
82 | }
83 | }
84 | ```
85 |
86 | 步骤:
87 |
88 | 1. installDecor()
89 | 2. 将布局填充到 mContentParent
90 | 3. 回调 Activity.onContentChanged
91 |
92 | PS:关于 LayoutInflater 如果你不懂它的原理,可以看看[LayoutInflater源码分析系列](./LayoutInflater.md)
93 |
94 | 接下去需要看 installDecor 方法。
95 |
96 | 问自己一下,这个 Decor 是什么?
97 |
98 | ### installDecor 解析
99 |
100 | ```
101 | // 在installDecor中调用,为方便查看,挪前面了。
102 | protected DecorView generateDecor() {
103 | return new DecorView(getContext(), -1);
104 | }
105 |
106 | private void installDecor() {
107 | // private DecorView mDecor;
108 | if (mDecor == null) {
109 | // 实例化一个 DecorView ,哦,原来是个 View 啊~
110 | mDecor = generateDecor();
111 | mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
112 | mDecor.setIsRootNamespace(true);
113 | if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
114 | mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
115 | }
116 | }
117 | // 为 null 才走,也就是说只会执行一遍~~
118 | if (mContentParent == null) {
119 | mContentParent = generateLayout(mDecor);
120 |
121 | // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
122 | mDecor.makeOptionalFitsSystemWindows();
123 |
124 | final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
125 | R.id.decor_content_parent);
126 |
127 | if (decorContentParent != null) {
128 | mDecorContentParent = decorContentParent;
129 | mDecorContentParent.setWindowCallback(getCallback());
130 | // 省略大段代码
131 | } else {
132 | // 标题
133 | mTitleView = (TextView)findViewById(R.id.title);
134 | if (mTitleView != null) {
135 | mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
136 | // 如果 NO_TITLE 则隐藏
137 | if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
138 | View titleContainer = findViewById(
139 | R.id.title_container);
140 | if (titleContainer != null) {
141 | titleContainer.setVisibility(View.GONE);
142 | } else {
143 | mTitleView.setVisibility(View.GONE);
144 | }
145 | if (mContentParent instanceof FrameLayout) {
146 | ((FrameLayout)mContentParent).setForeground(null);
147 | }
148 | } else {
149 | mTitleView.setText(mTitle);
150 | }
151 | }
152 | }
153 | //处理背景
154 | if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
155 | mDecor.setBackgroundFallback(mBackgroundFallbackResource);
156 | }
157 |
158 | // Only inflate or create a new TransitionManager if the caller hasn't
159 | // already set a custom one.
160 | if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
161 | //处理 Transition 这里不关心,就省略代码了。
162 | }
163 | }
164 | }
165 | ```
166 |
167 |
168 | 这边可以看到 Decor 其实是 DecorView,瞥一眼它的定义:
169 |
170 | ```
171 | // PhoneWindow$DecorView
172 | // top-level view of the window, containing the window decor
173 | private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
174 | ```
175 |
176 | 它是一个 Window 最最最顶层的 View。至于它为什么叫做`Decor`View,后面解释。
177 |
178 | 接下去看看 DecorView 的生成。
179 |
180 |
181 | ### generateLayout 方法解析
182 |
183 | generateLayout 方法的实现:
184 |
185 | ```
186 | // 该方法有 317行,不把重要的东西筛选出来看不懂
187 | protected ViewGroup generateLayout(DecorView decor) {
188 | // Apply data from current theme.
189 |
190 | TypedArray a = getWindowStyle();
191 | // 处理各种 FEATURE Window 属性,如 FEATURE_NO_TITLE Floating statusBarColor 啊 CloseOnTouchOutside啊 各种
192 | mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
193 | // ...
194 | if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
195 | requestFeature(FEATURE_NO_TITLE);
196 | } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
197 | // Don't allow an action bar if there is no title.
198 | requestFeature(FEATURE_ACTION_BAR);
199 | }
200 | //...
201 | if (!mForcedStatusBarColor) {
202 | mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
203 | }
204 | // ...
205 | WindowManager.LayoutParams params = getAttributes();
206 | // 处理各种属性
207 | //.....
208 |
209 | // The rest are only done if this window is not embedded; otherwise,
210 | // the values are inherited from our container.
211 | // 如果没有父 Window 那么获取一些属性 比如windowBackground
212 | // 想想 PopupWindow 这些需要依附到 Activity 的
213 | if (getContainer() == null) {
214 | //... 获取一些属性
215 | }
216 | // Inflate the window decor.
217 | int layoutResource;
218 | int features = getLocalFeatures();
219 | // System.out.println("Features: 0x" + Integer.toHexString(features));
220 | //... 根据 features 赋值 layoutResource
221 | // 取值有一些如 R.layout.screen_simple R.layout.screen_action_bar
222 | // ...
223 | layoutResource = R.layout.XXXXXX;
224 | // ...
225 |
226 | mDecor.startChanging();
227 | // 把 layoutResource 实例化成 View
228 | View in = mLayoutInflater.inflate(layoutResource, null);
229 | // 把 in 添加到 decor
230 | decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
231 | mContentRoot = (ViewGroup) in;
232 | // 提示一下 ID_ANDROID_CONTENT = com.android.internal.R.id.content
233 | ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
234 | if (contentParent == null) {
235 | throw new RuntimeException("Window couldn't find content container view");
236 | }
237 |
238 | //...
239 |
240 | // Remaining setup -- of background and title -- that only applies
241 | // to top-level windows.
242 | // 去设置 背景和 title
243 | if (getContainer() == null) {
244 | final Drawable background;
245 | if (mBackgroundResource != 0) {
246 | background = getContext().getDrawable(mBackgroundResource);
247 | } else {
248 | background = mBackgroundDrawable;
249 | }
250 | // 设置背景
251 | mDecor.setWindowBackground(background);
252 |
253 | final Drawable frame;
254 | if (mFrameResource != 0) {
255 | frame = getContext().getDrawable(mFrameResource);
256 | } else {
257 | frame = null;
258 | }
259 | mDecor.setWindowFrame(frame);
260 | mDecor.setElevation(mElevation);
261 | mDecor.setClipToOutline(mClipToOutline);
262 | if (mTitle != null) {
263 | setTitle(mTitle);
264 | }
265 | if (mTitleColor == 0) {
266 | mTitleColor = mTextColor;
267 | }
268 | setTitleColor(mTitleColor);
269 | }
270 |
271 | mDecor.finishChanging();
272 | // 返回了 R.id.content 的那个 View
273 | return contentParent;
274 | }
275 |
276 |
277 |
278 |
279 | 另外提一下,我们知道 requestFeature 需要在 setContentView之前调用就是因为在setContentView里把mContentParent实例化了。
280 |
281 |
--------------------------------------------------------------------------------
/ask-myself.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Application 谁创建的?
5 | mInstrumentation.newApplication
6 |
7 | Activity 谁创建的 ?
8 |
9 | mInstrumentation.newActivity
--------------------------------------------------------------------------------
/context-getsystemservice.md:
--------------------------------------------------------------------------------
1 | # Context.getSystemService分析
2 |
3 |
4 | ## 引言
5 |
6 | Context.getSystemService(String) 方法是我们用来获取各种系统服务的手段,比如:
7 |
8 | ```
9 | LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
10 |
11 | ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
12 | ```
13 |
14 | BONUS:像这样传入不同的参数(或 String 或 int),返回不同的对象,通常称为『工厂方法』。
15 |
16 |
17 | 那么问题来了:**这些服务是从哪里来的呢?**
18 |
19 | 在[Android应用的程序入口是哪里?](where-is-app's-entrance.md)一文中我们知道了,我们App的 Context 的实例实际是 ContextImpl的实例,所以需要去它那边研究。
20 |
21 | 接下去分析。
22 |
23 | ## 深入分析
24 |
25 | 看看 ContextImpl 的 getSystemService:
26 |
27 | ```
28 | @Override
29 | public Object getSystemService(String name) {
30 | return SystemServiceRegistry.getSystemService(this, name);
31 | }
32 | ```
33 |
34 | 发现调用了 SystemServiceRegistry.getSystemService:
35 |
36 | ```
37 | // SystemServiceRegistry
38 | public static Object getSystemService(ContextImpl ctx, String name) {
39 | ServiceFetcher> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
40 | return fetcher != null ? fetcher.getService(ctx) : null;
41 | }
42 | ```
43 |
44 | SystemServiceRegistry 是什么?ServiceFetcher又是什么?
45 |
46 | 当切换到一个新的不熟悉的类的时候,先不要着急,先看看这个类的介绍、结构与方法等,先大致了解一下,再继续深入研究。
47 |
48 | ### SystemServiceRegistry
49 |
50 | 来看看 SystemServiceRegistry 的定义以及我画的类图:
51 |
52 | ```
53 | /**
54 | * Manages all of the system services that can be returned by {@link Context#getSystemService}.
55 | * Used by {@link ContextImpl}.
56 | */
57 | final class SystemServiceRegistry{}
58 | ```
59 |
60 |
61 |
62 | 可以清楚的看到,SystemServiceRegistry 是『用来管理所有 ContextImpl.getSystemService 所返回的系统服务』的; ServiceFetcher 则是一个泛型接口。
63 |
64 | 那么是如何管理的呢?
65 |
66 | #### 系统服务的注册
67 |
68 | 在 SystemServiceRegistry 中有一个`static`块,代码是这样的:
69 |
70 | ```
71 | static{
72 | registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
73 | new CachedServiceFetcher() {
74 | @Override
75 | public LayoutInflater createService(ContextImpl ctx) {
76 | return new PhoneLayoutInflater(ctx.getOuterContext());
77 | }});
78 |
79 | registerService(Context.ALARM_SERVICE, AlarmManager.class,
80 | new CachedServiceFetcher() {
81 | @Override
82 | public AlarmManager createService(ContextImpl ctx) {
83 | IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
84 | IAlarmManager service = IAlarmManager.Stub.asInterface(b);
85 | return new AlarmManager(service, ctx);
86 | }});
87 | //...
88 | }
89 | ```
90 |
91 | 我挑了两个例子展示,省略了其他的系统服务注册代码,因为实际上,生成系统服务,就这两种方式:
92 |
93 | 1. 一种是 直接实例化对象,如`PhoneLayoutInflater`是直接`new`出来的。
94 | 2. 另外一种是从`ServiceManager.getService(String)`获取的。
95 |
96 | PS:ServiceManager 涉及到了 ServiceManagerNative、Binder、Binder 驱动等相关知识,非常复杂,这里不展开去研究,以后会有机会讲。
97 |
98 | **原来是在 static 代码块里注册了所有的系统服务**。
99 |
100 | #### 系统服务的缓存实现
101 |
102 | 像这种系统服务一般都是大对象,单例,不可能每次获取都是去新建。
103 |
104 | 所以当然会有缓存啦。
105 |
106 | 这个缓存在 ContextImpl 中
107 |
108 | ```
109 | final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
110 | ```
111 |
112 | 至于存入缓存的时机,需要看一个 ServiceFetcher 的实现(其他几个原理类似)
113 |
114 | ```
115 | // SystemServiceRegistry
116 | static abstract class CachedServiceFetcher implements ServiceFetcher {
117 | private final int mCacheIndex;
118 |
119 | public CachedServiceFetcher() {
120 | mCacheIndex = sServiceCacheSize++;
121 | }
122 |
123 | @Override
124 | @SuppressWarnings("unchecked")
125 | public final T getService(ContextImpl ctx) {
126 | // 获取缓存
127 | final Object[] cache = ctx.mServiceCache;
128 | synchronized (cache) {
129 | // Fetch or create the service.
130 | Object service = cache[mCacheIndex];
131 | // 如果缓存里没有 则调用 createService 去生成。
132 | if (service == null) {
133 | service = createService(ctx);
134 | cache[mCacheIndex] = service;
135 | }
136 | return (T)service;
137 | }
138 | }
139 |
140 | public abstract T createService(ContextImpl ctx);
141 | }
142 | ```
143 |
144 | ServiceFetcher.getService 被调用的时候会去判断是否有缓存,如果没有再调用 createService 去创建,再放入缓存,很简单的逻辑。
145 |
146 | ## 小结
147 |
148 | 我们 Context.getSystemService 获取到的系统服务其实从 SystemServiceRegistry 来,它负责注册以及管理系统服务。
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/done_list.md:
--------------------------------------------------------------------------------
1 | ## 目录
2 |
3 | [ViewStub 源码分析](./ViewStub.md)
4 | [Space 源码分析](./Space.md)
5 |
6 | [LayoutInflater 源码分析(一)之 inflate 深度分析](./LayoutInflater.md)
7 | [LayoutInflater 源码分析(二)之 include 以及 merge 标签的处理](./LayoutInflater-2.md)
8 | [LayoutInflater 源码分析(三)之 fragment 标签的处理](LayoutInflater-3.md)
9 | [LayoutInflater 源码分析(四)之 闪耀的彩蛋](./BlinkLayout.md)
10 |
11 | [invalidate和postInvalidate的关系与区别](invalidate-and-postinvalidate.md)
12 | [Android应用的程序入口是哪里?](where-is-app's-entrance.md)
--------------------------------------------------------------------------------
/fresco/Fresco.md:
--------------------------------------------------------------------------------
1 | # Fresco
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/imgs/LayoutInflate-attach2root.gliffy:
--------------------------------------------------------------------------------
1 | {"contentType":"application/gliffy+json","version":"1.1","metadata":{"title":"untitled","revision":0,"exportBorder":false},"embeddedResources":{"index":0,"resources":[]},"stage":{"objects":[{"x":507,"y":336,"rotation":0,"id":101,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":101,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-2,-3.5],[-2,84]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":96,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":99,"px":0.5,"py":0}}},"linkMap":[]},{"x":455,"y":420,"rotation":0,"id":99,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":99,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":103,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"result = temp;
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":440,"y":222.5,"rotation":0,"id":96,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.decision","width":130,"height":110,"lockAspectRatio":false,"lockShape":false,"order":96,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.diamond.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2.5999999999999996,"y":0,"rotation":0,"id":98,"uid":null,"width":124.8,"height":28,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"root==null||!attachToRoot
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":191,"y":424,"rotation":0,"id":91,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":91,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":true,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-1,-4],[-51,-4],[-51,106]],"lockSegments":{}}},"children":[{"x":0,"y":0,"rotation":0,"id":94,"uid":null,"width":38,"height":16,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"both","vposition":"none","hposition":"none","html":"TRUE
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":72,"px":0,"py":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":87,"px":0.5,"py":0}}},"linkMap":[]},{"x":90,"y":530,"rotation":0,"id":87,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":87,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":95,"uid":null,"width":96,"height":32,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"root.addView(temp, params)
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":290,"y":424,"rotation":0,"id":81,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":81,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#ff0000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":true,"interpolationType":"linear","cornerRadius":null,"controlPath":[[0,-4],[80,-4],[80,106]],"lockSegments":{}}},"children":[{"x":0,"y":0,"rotation":0,"id":85,"uid":null,"width":44,"height":16,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"both","vposition":"none","hposition":"none","html":"FALSE
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":72,"px":1,"py":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":78,"px":0.5,"py":0}}},"linkMap":[]},{"x":320,"y":530,"rotation":0,"id":78,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":78,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":86,"uid":null,"width":96,"height":28,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"temp.setLayoutParams(params)
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":244,"y":319,"rotation":0,"id":75,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":75,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#ff0000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-4,-4],[-4,51]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":58,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":72,"px":0.5,"py":0}}},"linkMap":[]},{"x":190,"y":370,"rotation":0,"id":72,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.decision","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":72,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.diamond.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":74,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"attachToRoot?
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":370,"y":81,"rotation":0,"id":69,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":69,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[0,-1],[0,39]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":53,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":55,"px":0.5,"py":0}}},"linkMap":[]},{"x":423,"y":173,"rotation":0,"id":65,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":65,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":true,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-3,-3],[82,-3],[82,49.5]],"lockSegments":{}}},"children":[{"x":0,"y":0,"rotation":0,"id":67,"uid":null,"width":33,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"both","vposition":"none","hposition":"none","html":"TRUE
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"constraints":{"constraints":[],"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":96,"px":0.5,"py":0}}},"linkMap":[]},{"x":322,"y":175,"rotation":0,"id":64,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":64,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#ff0000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":3,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":true,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-2,-5],[-82,-5],[-82,65]],"lockSegments":{}}},"children":[{"x":0,"y":0,"rotation":0,"id":66,"uid":null,"width":37,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"both","vposition":"none","hposition":"none","html":"FALSE
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":55,"px":0,"py":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":58,"px":0.5,"py":0}}},"linkMap":[]},{"x":190,"y":240,"rotation":0,"id":58,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":58,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":68,"uid":null,"width":96,"height":42,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"params = root.generateLayoutParams
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":320,"y":120,"rotation":0,"id":55,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.decision","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":55,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.diamond.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":57,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"root==null?
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":320,"y":30,"rotation":0,"id":53,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.start_end","width":100,"height":50,"lockAspectRatio":false,"lockShape":false,"order":53,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.start_end.flowchart_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":83,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"inflate
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]}],"background":"#FFFFFF","width":570,"height":605,"maxWidth":5000,"maxHeight":5000,"nodeIndex":104,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":true,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"shapeStyles":{"com.gliffy.shape.flowchart.flowchart_v1.default":{"fill":"#FFFFFF","stroke":"#333333","strokeWidth":2}},"lineStyles":{"global":{"stroke":"#ff0000","strokeWidth":2,"dashStyle":null,"endArrow":3,"orthoMode":0}},"textStyles":{},"themeData":null}}
--------------------------------------------------------------------------------
/imgs/SystemServiceRegistry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RTFSC-Android/RTFSC/650f9dbe4791029d8ab385088233c0b1d7288a18/imgs/SystemServiceRegistry.png
--------------------------------------------------------------------------------
/imgs/retrofit.gliffy:
--------------------------------------------------------------------------------
1 | {"contentType":"application/gliffy+json","version":"1.1","metadata":{"title":"untitled","revision":0,"exportBorder":false},"embeddedResources":{"index":0,"resources":[]},"stage":{"objects":[{"x":127,"y":428,"rotation":0,"id":37,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":37,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-2,-3],[-2,22]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":22,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":26,"px":0.5,"py":0}}},"linkMap":[]},{"x":126,"y":317,"rotation":0,"id":36,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":36,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-1,-2],[-1,33]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":15,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":22,"px":0.5,"py":0}}},"linkMap":[]},{"x":50,"y":350,"rotation":0,"id":22,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":150,"height":75,"lockAspectRatio":false,"lockShape":false,"order":22,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":3,"y":0,"rotation":0,"id":25,"uid":null,"width":144,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"SimpleCallAdapter.adapt
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":126,"y":199,"rotation":0,"id":20,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":20,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-1,-4],[-1,41]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":12,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":15,"px":0.5,"py":0}}},"linkMap":[]},{"x":40,"y":240,"rotation":0,"id":15,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":170,"height":75,"lockAspectRatio":false,"lockShape":false,"order":15,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":3.3999999999999986,"y":0,"rotation":0,"id":17,"uid":null,"width":163.19999999999996,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"callAdapter.adapt(okHttpCall)
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":75,"y":20,"rotation":0,"id":9,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":9,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":11,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"Retrofit.create
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":121,"y":858,"rotation":0,"id":52,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":52,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[4,-3],[4,32]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":40,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":49,"px":0.5,"py":0}}},"linkMap":[]},{"x":75,"y":890,"rotation":0,"id":49,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":49,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":51,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"Observable<R>
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":122.625,"y":725,"rotation":0,"id":42,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":42,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[2.375,0],[2.375,55]],"lockSegments":{}}},"children":[{"x":0,"y":0,"rotation":0,"id":43,"uid":null,"width":129,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"both","vposition":"none","hposition":"none","html":"Converter.convert(body)
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":32,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":40,"px":0.5,"py":0}}},"linkMap":[]},{"x":75,"y":780,"rotation":0,"id":40,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":100,"height":75,"lockAspectRatio":false,"lockShape":false,"order":40,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2,"y":0,"rotation":0,"id":45,"uid":null,"width":96,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"Response
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":129.25,"y":626,"rotation":0,"id":39,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":39,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-4.25,-1],[-4.25,24]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":29,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":32,"px":0.5,"py":0}}},"linkMap":[]},{"x":130.625,"y":531,"rotation":0,"id":38,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":38,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-5.625,-6],[-5.625,19]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":26,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":29,"px":0.5,"py":0}}},"linkMap":[]},{"x":58.75,"y":650,"rotation":0,"id":32,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":132.5,"height":75,"lockAspectRatio":false,"lockShape":false,"order":32,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2.6499999999999995,"y":0,"rotation":0,"id":35,"uid":null,"width":127.19999999999999,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"okhttp3.call.execute()
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":58.75,"y":550,"rotation":0,"id":29,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":132.5,"height":75,"lockAspectRatio":false,"lockShape":false,"order":29,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2.6500000000000004,"y":0,"rotation":0,"id":31,"uid":null,"width":127.20000000000003,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"OkHttpCall.execute()
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":57.5,"y":450,"rotation":0,"id":26,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":135,"height":75,"lockAspectRatio":false,"lockShape":false,"order":26,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2.7,"y":0,"rotation":0,"id":28,"uid":null,"width":129.60000000000002,"height":14,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"CallOnSubscribe.call
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]},{"x":128,"y":96,"rotation":0,"id":18,"uid":"com.gliffy.shape.basic.basic_v1.default.line","width":100,"height":100,"lockAspectRatio":false,"lockShape":false,"order":18,"graphic":{"type":"Line","Line":{"strokeWidth":2,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":1,"startArrowRotation":"auto","endArrowRotation":"auto","ortho":false,"interpolationType":"linear","cornerRadius":null,"controlPath":[[-3,-1],[-3,24]],"lockSegments":{}}},"children":null,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":9,"px":0.5,"py":1}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":12,"px":0.5,"py":0}}},"linkMap":[]},{"x":65,"y":120,"rotation":0,"id":12,"uid":"com.gliffy.shape.flowchart.flowchart_v1.default.process","width":120,"height":75,"lockAspectRatio":false,"lockShape":false,"order":12,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dropShadow":false,"state":0,"shadowX":0,"shadowY":0,"opacity":1}},"children":[{"x":2.4,"y":0,"rotation":0,"id":14,"uid":null,"width":115.19999999999999,"height":28,"lockAspectRatio":false,"lockShape":false,"order":"auto","graphic":{"type":"Text","Text":{"tid":null,"valign":"middle","overflow":"none","vposition":"none","hposition":"none","html":"loadServiceMethod\n
new OkHttpCall
","paddingLeft":2,"paddingRight":2,"paddingBottom":2,"paddingTop":2}},"children":null}],"linkMap":[]}],"background":"#FFFFFF","width":210,"height":965,"maxWidth":5000,"maxHeight":5000,"nodeIndex":56,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":true,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"shapeStyles":{"com.gliffy.shape.basic.basic_v1.default":{"fill":"#FFFFFF","stroke":"#333333","strokeWidth":2},"com.gliffy.shape.flowchart.flowchart_v1.default":{"fill":"#FFFFFF","stroke":"#333333","strokeWidth":2}},"lineStyles":{"global":{"endArrow":1}},"textStyles":{},"themeData":null}}
--------------------------------------------------------------------------------
/important-classes.md:
--------------------------------------------------------------------------------
1 | # 重要的类释义
2 |
3 |
4 | 记录一些非常重要或者平时看不到的类的信息,以及自己对它们的理解。
5 |
6 | `com.android.internal.policy.PhoneWindow` Android-specific Window. Activity 所拥有的 Window 就是 PhoneWindow
7 |
8 | // This is the top-level view of the window, containing the window decor.
9 | PhoneWindow.DecorView mDecor;
10 |
11 |
12 | Instrumentation
13 |
14 | LoadedApk
15 |
16 | ActivityThread
17 | ActivityThread$H
18 | ActivityThread$ActivityClientRecord
19 |
20 | ViewRootImpl
21 |
22 |
23 | WindowManager
24 | WindowManagerImpl.addView
25 | WindowManagerGlobal.addView
26 | ViewRootImpl.setView
--------------------------------------------------------------------------------
/intro-activitythread.md:
--------------------------------------------------------------------------------
1 | # ActivityThread
2 |
3 | 在这里记录我对 ActivityThread 的认知。
4 |
5 | ## 简介
6 |
7 | package android.app;
8 | public final class ActivityThread
9 |
10 |
11 | 在[Android应用程序的入口是哪里?](./where-is-app's-entrance.md)中已经有过简单介绍。
12 |
13 |
14 | ActivityThread 在很多文章中常被称为 主线程。
15 |
16 | 这个说法并不准确,因为其实它并不是一个线程,只是主线程调用了AactivityThread的main方法,所以我觉得把 ActivityThread 称作『主线程的入口』会更加合适一些。
17 |
18 | PS: ActivityThread的main方法是在 ZygoteInit.invokeStaticMain 中通过反射调用。
19 |
20 |
21 |
22 | ## ActivityThread.main 分析
23 |
24 | 来看一下`main`方法:
25 |
26 | ```
27 | public static void main(String[] args) {
28 | Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
29 | SamplingProfilerIntegration.start();
30 |
31 | // CloseGuard defaults to true and can be quite spammy. We
32 | // disable it here, but selectively enable it later (via
33 | // StrictMode) on debug builds, but using DropBox, not logs.
34 | CloseGuard.setEnabled(false);
35 | Environment.initForCurrentUser();
36 | // Set the reporter for event logging in libcore
37 | EventLogger.setReporter(new EventLoggingReporter());
38 | AndroidKeyStoreProvider.install();
39 | // Make sure TrustedCertificateStore looks in the right place for CA certificates
40 | final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
41 | TrustedCertificateStore.setDefaultUserDirectory(configDir);
42 |
43 | Process.setArgV0("");
44 | // 开始看得懂了对不对?
45 | // 准备主线程的 Looper
46 | Looper.prepareMainLooper();
47 | // 实例化 ActivityThread 并调用 attach 并传入了 false
48 | ActivityThread thread = new ActivityThread();
49 | thread.attach(false);
50 | // 主线程的 Handler
51 | if (sMainThreadHandler == null) {
52 | sMainThreadHandler = thread.getHandler();
53 | }
54 |
55 | if (false) {
56 | Looper.myLooper().setMessageLogging(new
57 | LogPrinter(Log.DEBUG, "ActivityThread"));
58 | }
59 | // End of event ActivityThreadMain.
60 | Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
61 | // 开始循环
62 | Looper.loop();
63 |
64 | throw new RuntimeException("Main thread loop unexpectedly exited");
65 | }
66 |
67 | // 从 main 方法过来的是 false PS:另外一个方法 systemMain()中会传入 true
68 | private void attach(boolean system) {
69 |
70 | sCurrentActivityThread = this;
71 | mSystemThread = system;
72 |
73 | if (!system) {
74 | // false 走这里
75 | // ...
76 | // 重要的在这里
77 | final IActivityManager mgr = ActivityManagerNative.getDefault();
78 | try {
79 | mgr.attachApplication(mAppThread);
80 | } catch (RemoteException ex) {
81 | // Ignore
82 | }
83 | //...BinderInternal.addGcWatcher(new Runnable() {});
84 |
85 | } else {
86 | //... 不走这里 省略
87 | }
88 |
89 | //... ViewRootImpl.addConfigCallback onConfigurationChanged
90 |
91 | }
92 | ```
93 |
94 | 暂时先不管那些个看不懂的方法,挑我们看得懂的。
95 |
96 | ActivityThread 的 main 方法中,主要做了以下步骤(挑了重点):
97 |
98 | - 1.为主线程准备了 Looper
99 | - 2.实例化 ActivityThread 并调用它的 attach 方法
100 | - 3.在 attach 方法中,又做了如下几件事
101 | - 1.获取 IActivityManager mgr
102 | - 2.调用 mgr.attachApplication (涉及到 AMS与 IApplicationThread 的交互)
103 | - 4. 把主线程的Handler `sMainThreadHandler` 赋值为 ActivityThread.mH
104 | - 5. Looper.loop(); 循环消息
105 |
106 |
107 | 从以上步骤来看,ActivityThread 对 App 的重要程度可见一斑。
108 |
109 | 再看 ActivityThread 的方法,有一系列的`performXXXActivity`和`handleXXXActivity`。
110 |
111 | 其实在 Activity 的启动流程中,ActivityThread的IApplicationThread 与 AMS 的交互最后都会走到 ActivityThread 来。
112 |
113 | 比如启动一个 Activity,会调用到 ActivityThread.performLaunchActivity 方法,已这个方法为例。
114 |
115 | ## performLaunchActivity 分析
116 |
117 |
118 | ```
119 | //ActivityThread
120 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
121 | // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
122 | //...
123 | Activity activity = null;
124 | try {
125 | java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
126 | // 创建 activity
127 | activity = mInstrumentation.newActivity(
128 | cl, component.getClassName(), r.intent);
129 | StrictMode.incrementExpectedActivityCount(activity.getClass());
130 | r.intent.setExtrasClassLoader(cl);
131 | r.intent.prepareToEnterProcess();
132 | if (r.state != null) {
133 | r.state.setClassLoader(cl);
134 | }
135 | } catch (Exception e) {
136 | //...
137 | }
138 |
139 | try {
140 | // 创建 App 方法的实现看后面 是个 单例实现
141 | Application app = r.packageInfo.makeApplication(false, mInstrumentation);
142 | //...
143 | if (activity != null) {
144 | Context appContext = createBaseContextForActivity(r, activity);
145 | CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
146 | //...
147 | // 调用 activity.attach
148 | activity.attach(appContext, this, getInstrumentation(), r.token,
149 | r.ident, app, r.intent, r.activityInfo, title, r.parent,
150 | r.embeddedID, r.lastNonConfigurationInstances, config,
151 | r.referrer, r.voiceInteractor);
152 |
153 | //...
154 | //...调用Activity 的生命周期等 mInstrumentation.callActivityOnCreate
155 |
156 | }
157 | r.paused = true;
158 |
159 | mActivities.put(r.token, r);
160 |
161 | } catch (SuperNotCalledException e) {
162 | throw e;
163 | } catch (Exception e) {
164 | //...
165 | }
166 | return activity;
167 | }
168 |
169 | // LoadedApk.makeApplication
170 | public Application makeApplication(boolean forceDefaultAppClass,
171 | Instrumentation instrumentation) {
172 | //保证了 Application 单例
173 | if (mApplication != null) {
174 | return mApplication;
175 | }
176 |
177 | Application app = null;
178 |
179 | String appClass = mApplicationInfo.className;
180 | if (forceDefaultAppClass || (appClass == null)) {
181 | appClass = "android.app.Application";
182 | }
183 |
184 | try {
185 | java.lang.ClassLoader cl = getClassLoader();
186 | if (!mPackageName.equals("android")) {
187 | initializeJavaContextClassLoader();
188 | }
189 | // 创建 ContextImpl
190 | ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
191 | // 创建我们的 Application
192 | app = mActivityThread.mInstrumentation.newApplication(
193 | cl, appClass, appContext);
194 | appContext.setOuterContext(app);
195 | } catch (Exception e) {
196 | //...
197 | }
198 | mActivityThread.mAllApplications.add(app);
199 | mApplication = app;
200 |
201 | if (instrumentation != null) {
202 | try {
203 | // 调用 Application.OnCreate
204 | instrumentation.callApplicationOnCreate(app);
205 | } catch (Exception e) {
206 | //...
207 | }
208 | }
209 | //.... Rewrite the R 'constants' for all library apks.
210 | // Rewrite the R 'constants' for all library apks.
211 |
212 | return app;
213 | }
214 |
215 | // Instrumentation
216 | public void callApplicationOnCreate(Application app) {
217 | app.onCreate();
218 | }
219 | ```
220 |
221 | 代码稍微有点多,删减了大部分暂时不关心的代码。
222 |
223 | 可以看到
224 |
225 | Instrumentation.newApplication 创建了 Application,Instrumentation.callApplicationOnCreate 里调用了 Application 的 onCreate。
226 |
227 | 看到上面所说的步骤都非常重要,主线程Looper的创建、ContextImpl的创建、Application的创建以及onCreate 回调,这些都跟 App 息息相关。
228 |
229 |
230 | ## 小结
231 |
232 | ActivityThread
233 | Instrumentation
234 | LoadedApk
235 | IApplicationThread
236 |
--------------------------------------------------------------------------------
/invalidate-and-postinvalidate.md:
--------------------------------------------------------------------------------
1 | # invalidate和postInvalidate的关系与区别
2 |
3 |
4 | ## 引言
5 |
6 | 当我们需要重绘一个 View 的时候(走 draw ),我们有两个方法可供选择,invalidate 和 postInvalidate。
7 |
8 | 那么它们之间的关系与区别是什么呢?
9 |
10 | 本篇从源码角度分析 invalidate 与 postInvalidate 之间的关系区别。
11 |
12 | ## 分析
13 |
14 | `invalidate`的代码调用路径:
15 |
16 | ```
17 | public void invalidate() {
18 | invalidate(true);
19 | }
20 |
21 | void invalidate(boolean invalidateCache) {
22 | invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
23 | }
24 | ```
25 |
26 | 可以看到 invalidate 最后调用 invalidateInternal 去刷新,这里暂时不关心它们的具体实现。
27 |
28 | 然后再看看`postInvalidate`的代码调用路径:
29 |
30 | ```
31 | public void postInvalidate(int left, int top, int right, int bottom) {
32 | postInvalidateDelayed(0, left, top, right, bottom);
33 | }
34 | /**
35 | * This method can be invoked from outside of the UI thread
36 | * only when this View is attached to a window.
37 | */
38 | public void postInvalidateDelayed(long delayMilliseconds) {
39 | // We try only with the AttachInfo because there's no point in invalidating
40 | // if we are not attached to our window
41 | final AttachInfo attachInfo = mAttachInfo;
42 | if (attachInfo != null) {
43 | attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
44 | }
45 | }
46 |
47 | // ViewRootImpl
48 | public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
49 | Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
50 | mHandler.sendMessageDelayed(msg, delayMilliseconds);
51 | }
52 |
53 | // ViewRootImpl$ViewRootHandler extends Handler
54 | @Override
55 | public void handleMessage(Message msg) {
56 | switch (msg.what) {
57 | case MSG_INVALIDATE:
58 | ((View) msg.obj).invalidate();
59 | break;
60 | case xxx:
61 | break;
62 | }
63 | }
64 | ```
65 |
66 | postInvalidate 其实是把 invalidate 这个操作封装成了一个 Message,post 到了 ViewRootImpl$ViewRootHandler 中去,最终在UI线程中调用了 View 的 invalidate。
67 |
68 | 我们知道,异步更新一个 View 会报`"Only the original thread that created a view hierarchy can touch its views."`(来自 ViewRootImplement$checkThread)的错误,
69 |
70 | 而 postInvalidate 可以在任意线程去调用,而不需要担心线程问题。
71 |
72 | PS:很多人说『一定要在主线程更新 UI』,其实不然,仔细看这报错信息指得是 original thread,而这个线程是创建 ViewRootImpl 的线程,而不是特指主线程,只不过是绝大部分情况下是主线程,仅此而已。
73 |
74 | ## 小结
75 |
76 | 关系:
77 | - postInvalidate 其实最终调用的就是 invalidate
78 |
79 | 差别:
80 | - invalidate只能在 original thread 调用(一般就是主线程),而 postInvalidate 可以在任意线程调用。
81 |
82 | 这结论其实早就知道了,但是光知道这结论是远远不够的,要深入源码去理解,找出结论的由来;
83 |
84 | 慢慢地,会发现,其实那些知识点以及结论其实就是从源码里得来的;
85 |
86 | 自己看源码,会收获更多意想不到的知识。
87 |
--------------------------------------------------------------------------------
/libraries/leakcanary/LeakCanary.md:
--------------------------------------------------------------------------------
1 | # LeakCanary内存泄漏检测原理分析
2 |
3 |
4 |
5 | ## 什么是内存泄漏
6 |
7 |
8 |
9 |
10 |
11 | ### 内存泄漏的危害
12 |
13 |
14 |
15 |
16 |
17 | ## 什么是LeakCanary
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```java
26 | public interface GcTrigger {
27 | GcTrigger DEFAULT = new GcTrigger() {
28 | public void runGc() {
29 | Runtime.getRuntime().gc();
30 | this.enqueueReferences();
31 | System.runFinalization();
32 | }
33 |
34 | private void enqueueReferences() {
35 | try {
36 | Thread.sleep(100L);
37 | } catch (InterruptedException var2) {
38 | throw new AssertionError();
39 | }
40 | }
41 | };
42 |
43 | void runGc();
44 | }
45 | ```
46 |
47 |
48 |
49 |
50 |
51 | ## 延伸阅读
52 |
53 | [LeakCanary: Detect all memory leaks!](https://medium.com/square-corner-blog/leakcanary-detect-all-memory-leaks-875ff8360745#.kqaeapqlx)
54 |
55 | [LeakCanary-FAQ](https://github.com/square/leakcanary/wiki/FAQ)
56 |
57 | [LeakCanary 内存泄露监测原理研究](http://www.jianshu.com/p/5ee6b471970e)
58 |
59 | [Android应用内存泄漏的定位、分析与解决策略](http://www.jianshu.com/p/96c55ea3446e#)
60 |
61 |
--------------------------------------------------------------------------------
/libraries/retrofit/how-retrofit-works.md:
--------------------------------------------------------------------------------
1 | # Retrofit是如何工作的?
2 |
3 | > 注:本文基于 Retrofit2.0版本,并配合 RxJava 来分析。
4 | >
5 | > com.squareup.retrofit2:retrofit:2.0.0
6 | >
7 | > com.squareup.retrofit2:converter-gson:2.0.0
8 | >
9 | > com.squareup.retrofit2:adapter-rxjava:2.0.0
10 |
11 |
12 |
13 | [Retrofit](https://square.github.io/retrofit/) adapts a Java interface to HTTP calls by using annotations on the declared methods to how requests are made.
14 |
15 | 本文主要通过分析 **Retrofit 与 RxJava 的合作流程** 来深入理解 Retrofit的工作原理,并且解答自己心中的疑惑。
16 |
17 | #### 疑惑
18 |
19 | 1. 我们调用接口的方法后是怎么发送请求的?这背后发生了什么?
20 | 2. Retrofit 与 OkHttp 是怎么合作的?
21 | 3. Retrofit 中的数据究竟是怎么处理的?它是怎么返回 RxJava.Observable 的?
22 |
23 |
24 |
25 | ## Retrofit 的基本使用
26 |
27 | ```java
28 | public interface ApiService{
29 | @GET("data/Android/"+ GankConfig.PAGE_COUNT+"/{page}")
30 | Observable getAndroid(@Path("page") int page);
31 | }
32 |
33 | // Builder 模式来构建 retrofit
34 | Retrofit retrofit = new Retrofit.Builder()
35 | .baseUrl(baseUrl)
36 | .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
37 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
38 | .client(okHttpClient)
39 | .build();
40 | // 通过 retrofit.create 方法来生成 service(非四大组件中的 Service)
41 | ApiService service = retrofit.create(ApiService.class);
42 | // 发起请求 获取数据
43 | Observable observable= service.getAndroid(1);
44 | observable....
45 | ```
46 |
47 |
48 |
49 | Retrofit 就这样经过简单的配置后就可以向服务器请求数据了,超级简单。
50 |
51 | ## Retrofit.create 方法分析
52 |
53 |
54 |
55 | Retrofit的`create`方法作为 Retrofit 的入口,当然得第一个分析。
56 |
57 |
58 |
59 | ```java
60 | public T create(final Class service) {
61 | //验证接口是否合理
62 | Utils.validateServiceInterface(service);
63 | //默认 false
64 | if (validateEagerly) {
65 | eagerlyValidateMethods(service);
66 | }
67 | // 动态代理
68 | return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
69 | new InvocationHandler() {
70 | // 平台的抽象,指定默认的 CallbackExecutor CallAdapterFactory用, 这里 Android 平台是 Android (Java8 iOS 咱不管)
71 | private final Platform platform = Platform.get();
72 | //ApiService 中的方法调用都会走到这里
73 | @Override public Object invoke(Object proxy, Method method, Object... args)
74 | throws Throwable {
75 | // If the method is a method from Object then defer to normal invocation.
76 | // 注释已经说明 Object 的方法不管
77 | if (method.getDeclaringClass() == Object.class) {
78 | return method.invoke(this, args);
79 | }
80 | // java8 的默认方法,Android暂不支持默认方法,所以暂时也不需要管
81 | if (platform.isDefaultMethod(method)) {
82 | return platform.invokeDefaultMethod(method, service, proxy, args);
83 | }
84 | // 重点了 后面分析
85 | // 为 Method 生成一个 ServiceMethod
86 | ServiceMethod serviceMethod = loadServiceMethod(method);
87 | // 再包装成 OkHttpCall
88 | OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); // 请求
89 | return serviceMethod.callAdapter.adapt(okHttpCall);
90 | }
91 | });
92 | }
93 | ```
94 |
95 |
96 |
97 | 在上面的代码中可以看到,Retrofit 的主要原理是利用了 Java 的**动态代理技术**,把 ApiService 的方法调用集中到了`InvocationHandler.invoke`,再构建了ServiceMethod ,OKHttpCall,返回 `callAdapter.adapt` 的结果。
98 |
99 | 要弄清楚,还需要分析那最后三行代码。
100 |
101 | 一步一步来。
102 |
103 | ## ServiceMethod的职责以及 loadServiceMethod分析
104 |
105 | 我认为 ServiceMethod 是接口**具体方法的抽象**,它主要负责解析它对应的 `method` 的各种参数(它有各种如 `parseHeaders` 的方法),比如注解(@Get),入参,另外还负责获取 callAdapter,responseConverter等Retrofit配置,好为后面的`okhttp3.Request`做好参数准备,它的`toRequest`为 OkHttp 提供 Request,可以说它承载了后续 Http 请求所需的一切参数。
106 |
107 |
108 |
109 | 再分析` loadServiceMethod`,比较简单。
110 |
111 | ```java
112 | // serviceMethodCache 的定义
113 | private final Map serviceMethodCache = new LinkedHashMap<>();
114 | // 获取method对应的 ServiceMethod
115 | ServiceMethod loadServiceMethod(Method method) {
116 | ServiceMethod result;
117 | synchronized (serviceMethodCache) {
118 | // 先从缓存去获取
119 | result = serviceMethodCache.get(method);
120 | if (result == null) {
121 | //缓存中没有 则新建,并存入缓存
122 | result = new ServiceMethod.Builder(this, method).build();
123 | serviceMethodCache.put(method, result);
124 | }
125 | }
126 | return result;
127 | }
128 | ```
129 |
130 |
131 |
132 | `loadServiceMethod`方法,负责 为 `method` 生成一个 ServiceMethod ,并且给 ServiceMethod 做了缓存。
133 |
134 | 动态代理是有一定的性能损耗的,并且ServiceMethod 的创建伴随着各种注解参数解析,这也是耗时间的,在加上一个 App 调用接口是非常频繁的,如果每次接口请求都需要重新生成那么有浪费资源损害性能的可能,所以这里做了一份缓存来提高效率。
135 |
136 |
137 |
138 | ## OkHttpCall
139 |
140 |
141 |
142 | 再接下去往后看`OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);`,是再为 ServiceMethod 以及 args(参数)生成了一个 `OkHttpCall`。
143 |
144 | 从 `OkHttpCall` 这个名字来看就能猜到,它是对 `OkHttp3.Call` 的组合包装,事实上,它也确实是。(`OkHttpCall`中有一个成员`okhttp3.Call rawCall`)。
145 |
146 |
147 |
148 | ## callAdapter.adapt流程分析
149 |
150 |
151 |
152 | 最后`return serviceMethod.callAdapter.adapt(okHttpCall)` 似乎是走到了最后一步。
153 |
154 | 如果说前面的都是准备的话,那么到这里就是真的要行动了。
155 |
156 |
157 |
158 | 来分析一下,这里涉及到的 `callAdapter`,是由我们配置 Retrofit 的 `addCallAdapterFactory`方法中传入的`RxJavaCallAdapterFactory.create()`生成,实例为`RxJavaCallAdapterFactory`。
159 |
160 | 实例的生成大致流程为:
161 |
162 |
163 |
164 | ServiceMethod.Bulider.Build()
165 |
166 | ->ServiceMethod.createCallAdapter()
167 |
168 | ->retrofit.callAdapter()
169 |
170 | ->adapterFactories遍历
171 |
172 | ->最终到RxJavaCallAdapterFactory.get()#getCallAdapter()
173 |
174 | ->return `return new SimpleCallAdapter(observableType, scheduler);`
175 |
176 |
177 |
178 | 由于使用了 RxJava ,我们最终得到的 `callAdapter` 为 `SimpleCallAdapter`,所以接下去分析`SimpleCallAdapter`的 `adapt` 方法:
179 |
180 | 这里涉及到的 `CallOnSubscriber` 后面有给出:
181 |
182 | ```java
183 | @Override public Observable adapt(Call call) {
184 | // 这里的 call 是 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args) 生成的 okHttpCall
185 | Observable observable = Observable.create(new CallOnSubscribe<>(call)) //
186 | .flatMap(new Func1, Observable>() {
187 | @Override public Observable call(Response response) {
188 | if (response.isSuccessful()) {
189 | return Observable.just(response.body());
190 | }
191 | return Observable.error(new HttpException(response));
192 | }
193 | });
194 | if (scheduler != null) {
195 | return observable.subscribeOn(scheduler);
196 | }
197 | return observable;
198 | }
199 | }
200 | ```
201 |
202 |
203 |
204 | ```java
205 | static final class CallOnSubscribe implements Observable.OnSubscribe> {
206 | private final Call originalCall;
207 |
208 | CallOnSubscribe(Call originalCall) {
209 | this.originalCall = originalCall;
210 | }
211 |
212 | @Override public void call(final Subscriber super Response> subscriber) {
213 | // Since Call is a one-shot type, clone it for each new subscriber.
214 | final Call call = originalCall.clone();
215 | // Attempt to cancel the call if it is still in-flight on unsubscription.
216 | // 当我们取消订阅的时候 会取消请求 棒棒哒
217 | subscriber.add(Subscriptions.create(new Action0() {
218 | @Override public void call() {
219 | call.cancel();
220 | }
221 | }));
222 |
223 | try {
224 | // call 是 OkHttpCall 的实例
225 | Response response = call.execute();
226 | if (!subscriber.isUnsubscribed()) {
227 | subscriber.onNext(response);
228 | }
229 | } catch (Throwable t) {
230 | Exceptions.throwIfFatal(t);
231 | if (!subscriber.isUnsubscribed()) {
232 | subscriber.onError(t);
233 | }
234 | return;
235 | }
236 |
237 | if (!subscriber.isUnsubscribed()) {
238 | subscriber.onCompleted();
239 | }
240 | }
241 | }
242 | ```
243 |
244 |
245 |
246 | SimpleCallAdapter.adapt 很简单,创建一个 Observable获取CallOnSubscribe中的Response 通过 flatMap转成Observable后返回。这里去发送请求获取数据的任务在CallOnSubscribe.call 方法之中。并且最后走到了 okHttpCall.execute 中去了。
247 |
248 |
249 |
250 | ```java
251 | // OkHttpCall.execute
252 |
253 | @Override public Response execute() throws IOException {
254 | okhttp3.Call call;
255 |
256 | synchronized (this) {
257 | //同一个请求 不能执行两次
258 | if (executed) throw new IllegalStateException("Already executed.");
259 | executed = true;
260 | // ...省略 Execption 处理
261 |
262 | call = rawCall;
263 | if (call == null) {
264 | try {
265 | // 创建 okhttp3.call
266 | call = rawCall = createRawCall();
267 | } catch (IOException | RuntimeException e) {
268 | creationFailure = e;
269 | throw e;
270 | }
271 | }
272 | }
273 | if (canceled) {
274 | call.cancel();
275 | }
276 | // 请求并解析response 这个 call 是 okhttp3.call 是真交给 OkHttp 去发送请求了
277 | return parseResponse(call.execute());
278 | }
279 |
280 | // 解析 response
281 | Response parseResponse(okhttp3.Response rawResponse) throws IOException {
282 | //... 省略一些处理 只显示关键代码
283 | try {
284 | T body = serviceMethod.toResponse(catchingBody);
285 | return Response.success(body, rawResponse);
286 | } catch (RuntimeException e) {
287 | catchingBody.throwIfCaught();
288 | throw e;
289 | }
290 | }
291 |
292 | // serviceMethod.toResponse
293 | T toResponse(ResponseBody body) throws IOException {
294 | // 还记得吗?这就是我们配置Retrofit时候的 converter
295 | return responseConverter.convert(body);
296 | }
297 | ```
298 |
299 |
300 |
301 | 经过一连串的处理,最终在 OkHttpCall.execute() 的方法中生成 okhttp3.call 交给 OkHttpClient 去发送请求,再由我们配置的 Converter(本文为GsonConverterFactory) 处理 Response,返回给SimpleCallAdapter处理,返回我们最终所需要的Observable。
302 |
303 |
304 |
305 | ## 流程分析流程图总结
306 |
307 | 分析结束,总体的流程图整理如下:
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 | ## 解答疑问
316 |
317 | 对于之前的疑问可以作答了。
318 |
319 | #### 第一个疑问: 我们调用接口的方法后是怎么发送请求的?这背后发生了什么?
320 |
321 | Retrofit 使用了动态代理给我们定义的接口设置了代理,当我们调用接口的方法时,Retrofit 会拦截下来,然后经过一系列处理,比如解析方法的注解等,生成了 Call Request 等OKHttp所需的资源,最后交给 OkHttp 去发送请求, 此间经过 callAdapter,convertr 的处理,最后拿到我们所需要的数据。
322 |
323 |
324 |
325 | #### 第二个疑问: Retrofit 与 OkHttp 是怎么合作的?
326 |
327 | 在Retrofit 中,ServiceMethod 承载了一个 Http 请求的所有参数,OkHttpCall 为 okhttp3.call 的组合包装,由它们俩合作,生成用于 OkHttp所需的 Request以及okhttp3.Call,交给 OkHttp 去发送请求。(在本文环境下具体用的是 `call.execute()`)
328 |
329 | 可以说 Retrofit 为 OkHttp 再封装了一层,并增添了不少功能以及扩展,减少了开发使用成本。
330 |
331 | #### 第三个疑问: Retrofit 中的数据究竟是怎么处理的?它是怎么返回 RxJava.Observable 的?
332 |
333 | Retrofit 中的数据其实是交给了 callAdapter 以及 converter 去处理,callAdapter 负责把 okHttpCall 转成我们所需的 Observable类型(本文环境),converter负责把服务器返回的数据转成具体的实体类。
334 |
335 | ## 小结
336 |
337 | Retrofit 的源码其实非常好跟也非常好理解,不像看 framework 的代码,跟着跟着就不见了。
338 |
339 | 另外 Retrofit的代码确实非常漂亮,将设计模式运用的可以说是炉火纯青,非常值得学习。
340 |
341 |
342 |
343 | ## 推荐文章
344 |
345 | [Retrofit分析-漂亮的解耦套路](http://www.jianshu.com/p/45cb536be2f4)
346 |
347 |
--------------------------------------------------------------------------------
/startactivity-flow.md:
--------------------------------------------------------------------------------
1 | # Activity的启动流程
2 |
3 |
4 | //todo 详细的分析
5 |
6 |
7 | 大致内容记录一下
8 |
9 | 太复杂了,吃不消。。。。。。
10 |
11 |
12 | ContextImpl.startActivity/Activity.startActivity
13 | => ActivityThread.mInstrumentation.execStartActivity
14 | => ActivityManagerNative.startActivity (IActivityManagerNative 的代理ActivityManagerProxy)
15 | => ActivityManagerProxy.startActivity
16 | => ActivityManagerService.startActivity
17 | => ActivityManagerService.startActivityAsUser
18 | => ActivityStackSupervisor.startActivityMayWait
19 | => ActivityStackSupervisor.startActivityLocked
20 | => ActivityStackSupervisor.startActivityUncheckedLocked
21 | => ActivityStack.startActivityLocked
22 | => ActivityStackSupervisor.resumeTopActivitiesLocked
23 | => ActivityStack.resumeTopActivitiesLocked
24 | => ActivityStack.resumeTopActivityInnerLocked
25 | .
26 | .
27 | .
28 | .
29 | => ActivityStackSupervisor.realStartActivityLocked
30 | => app.thread.scheduleLaunchActivity
31 | => ApplicationThreadProxy.scheduleLaunchActivity
32 | => ActivityThread.sendMessage
33 | => ActivityThread.mH.sendMessage & handleMessage
34 | => ActivityThread.handleLaunchActivity
35 | => performLaunchActivity
36 | => handleResumeActivity
37 |
38 | 差不多大致是这样的流程。。。。
39 |
40 | 心好累,还是有很多很多细节没有理清楚。
41 |
42 | ActivityManagerService 与 ActivityThread 之间用 ApplicationThread 来交互。
43 |
44 |
45 | ActivityStack或ActivityStackSupervisor 里会调用 ActivityRecod.app.thread (IApplicationThread)的 `scheduleXXXXActivity`比如 `schedulePauseActivity`
46 |
47 |
48 |
49 | [](http://blog.csdn.net/luoshengyang/article/details/6689748)
50 |
51 |
--------------------------------------------------------------------------------
/where-is-app's-entrance.md:
--------------------------------------------------------------------------------
1 | # Android应用程序的入口是哪里?
2 |
3 | ## 引言
4 |
5 | 一般我们都会认为Application的 onCreate 方法就是入口了,毕竟它算是第一个回调,我们通常在那做初始化。
6 |
7 | 不过 Application 的 onCreate 真的是程序的入口吗?它是什么时候调用被谁调用的呢?
8 |
9 | 我们知道 Android 基于 Java,而 Java 的入口其实是一个 `main` 方法,那么App的 `main` 方法在哪里呢?
10 |
11 | 所以,显然,入口并不是 Application.onCreate。
12 |
13 | 那么又是哪里呢?
14 |
15 | 这里要涉及到一个类`ActivityThread`,它拥有这个`main`方法。
16 |
17 | 让我们一探究竟。
18 |
19 | ## ActivityThread的main方法
20 |
21 | ActivityThread 位于`android.app`包下。
22 |
23 | 来看一下`main`方法:
24 |
25 | ```Java
26 | // android.app.ActivityThread
27 | public static void main(String[] args) {
28 | Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
29 | SamplingProfilerIntegration.start();
30 |
31 | // CloseGuard defaults to true and can be quite spammy. We
32 | // disable it here, but selectively enable it later (via
33 | // StrictMode) on debug builds, but using DropBox, not logs.
34 | CloseGuard.setEnabled(false);
35 | Environment.initForCurrentUser();
36 | // Set the reporter for event logging in libcore
37 | EventLogger.setReporter(new EventLoggingReporter());
38 | AndroidKeyStoreProvider.install();
39 | // Make sure TrustedCertificateStore looks in the right place for CA certificates
40 | final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
41 | TrustedCertificateStore.setDefaultUserDirectory(configDir);
42 |
43 | Process.setArgV0("");
44 | // 开始看得懂了对不对?
45 | // 准备主线程的 Looper
46 | Looper.prepareMainLooper();
47 | // 实例化 ActivityThread 并调用 attach 并传入了 false
48 | ActivityThread thread = new ActivityThread();
49 | thread.attach(false);
50 | // 主线程的 Handler
51 | if (sMainThreadHandler == null) {
52 | sMainThreadHandler = thread.getHandler();
53 | }
54 |
55 | if (false) {
56 | Looper.myLooper().setMessageLogging(new
57 | LogPrinter(Log.DEBUG, "ActivityThread"));
58 | }
59 | // End of event ActivityThreadMain.
60 | Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
61 | // 开始循环
62 | Looper.loop();
63 |
64 | throw new RuntimeException("Main thread loop unexpectedly exited");
65 | }
66 |
67 | // 从 main 方法过来的是 false PS:另外一个方法 systemMain()中会传入 true
68 | private void attach(boolean system) {
69 |
70 | sCurrentActivityThread = this;
71 | mSystemThread = system;
72 |
73 | if (!system) {
74 | // false 走这里
75 | // ...
76 | // 重要的在这里
77 | final IActivityManager mgr = ActivityManagerNative.getDefault();
78 | try {
79 | mgr.attachApplication(mAppThread);
80 | } catch (RemoteException ex) {
81 | // Ignore
82 | }
83 | //...BinderInternal.addGcWatcher(new Runnable() {});
84 |
85 | } else {
86 | //... 不走这里 省略
87 | }
88 |
89 | //... ViewRootImpl.addConfigCallback onConfigurationChanged
90 |
91 | }
92 | ```
93 |
94 | 暂时先不管那些个看不懂的方法,挑我们看得懂的。
95 |
96 | ActivityThread 的 main 方法中,主要做了以下步骤(挑重点):
97 |
98 | - 1.为主线程准备 Looper
99 | - 2.实例化 ActivityThread 并调用它的 attach 方法
100 | - 3.在 attach 方法中,又做了如下几件事
101 | - 1.获取 IActivityManager mgr
102 | - 2.调用 mgr.attachApplication
103 | - 4. 把主线程的Handler `sMainThreadHandler` 赋值为 ActivityThread.mH
104 | - 5. Looper.loop(); 循环消息
105 |
106 |
107 | 在3.2步骤中进行了非常复杂的操作,各种交互,这里不展开,最后在启动我们的启动页的时候,最终会调用到 ActivityThread.performLaunchActivity 方法。
108 |
109 |
110 | ```
111 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
112 | // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
113 |
114 | //...
115 |
116 | Activity activity = null;
117 | try {
118 | java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
119 | // 创建 activity
120 | activity = mInstrumentation.newActivity(
121 | cl, component.getClassName(), r.intent);
122 | StrictMode.incrementExpectedActivityCount(activity.getClass());
123 | r.intent.setExtrasClassLoader(cl);
124 | r.intent.prepareToEnterProcess();
125 | if (r.state != null) {
126 | r.state.setClassLoader(cl);
127 | }
128 | } catch (Exception e) {
129 | //...
130 | }
131 |
132 | try {
133 | // 创建 App 方法的实现看后面
134 | Application app = r.packageInfo.makeApplication(false, mInstrumentation);
135 | //...
136 | if (activity != null) {
137 | Context appContext = createBaseContextForActivity(r, activity);
138 | CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
139 | //...
140 | // 调用 activity.attach
141 | activity.attach(appContext, this, getInstrumentation(), r.token,
142 | r.ident, app, r.intent, r.activityInfo, title, r.parent,
143 | r.embeddedID, r.lastNonConfigurationInstances, config,
144 | r.referrer, r.voiceInteractor);
145 |
146 | //...
147 | //...调用Activity 的生命周期等 mInstrumentation.callActivityOnCreate
148 |
149 | }
150 | r.paused = true;
151 |
152 | mActivities.put(r.token, r);
153 |
154 | } catch (SuperNotCalledException e) {
155 | throw e;
156 | } catch (Exception e) {
157 | //...
158 | }
159 | return activity;
160 | }
161 |
162 | // LoadedApk.makeApplication
163 | public Application makeApplication(boolean forceDefaultAppClass,
164 | Instrumentation instrumentation) {
165 | //保证了 Application 单例
166 | if (mApplication != null) {
167 | return mApplication;
168 | }
169 |
170 | Application app = null;
171 |
172 | String appClass = mApplicationInfo.className;
173 | if (forceDefaultAppClass || (appClass == null)) {
174 | appClass = "android.app.Application";
175 | }
176 |
177 | try {
178 | java.lang.ClassLoader cl = getClassLoader();
179 | if (!mPackageName.equals("android")) {
180 | initializeJavaContextClassLoader();
181 | }
182 | // 创建 ContextImpl
183 | ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
184 | // 创建我们的 Application
185 | app = mActivityThread.mInstrumentation.newApplication(
186 | cl, appClass, appContext);
187 | appContext.setOuterContext(app);
188 | } catch (Exception e) {
189 | //...
190 | }
191 | mActivityThread.mAllApplications.add(app);
192 | mApplication = app;
193 |
194 | if (instrumentation != null) {
195 | try {
196 | // 调用 ApplicationOnCreate
197 | instrumentation.callApplicationOnCreate(app);
198 | } catch (Exception e) {
199 | //...
200 | }
201 | }
202 | //.... Rewrite the R 'constants' for all library apks.
203 | // Rewrite the R 'constants' for all library apks.
204 |
205 | return app;
206 | }
207 |
208 | // Instrumentation
209 | public void callApplicationOnCreate(Application app) {
210 | app.onCreate();
211 | }
212 | ```
213 |
214 | 代码稍微有点多,删减了大部分暂时不关心的代码。
215 |
216 | 可以看到
217 |
218 | `Instrumentation.newApplication` 创建了 Applicationd的实例,`Instrumentation.callApplicationOnCreate` 里调用了 `Application.onCreate`。
219 |
220 | 看到上面所说的步骤都非常重要,主线程Looper的创建、ContextImpl的创建、Application的创建以及onCreate 回调,这些都跟 App 息息相关。
221 |
222 | 也解答了我们之前的疑问。
223 |
224 | ## 小结
225 |
226 | **对于一个 App 来说其实 ActivityThread.main 才是真正的入口。**
227 |
228 | **UPDATE:上一句话的描述不太准确,对于ActivityThread是否是入口,有所争论,具体可以看后面我在知乎上的提问。**
229 |
230 | **Application 的创建以及 onCreate 的回调,都由 Instrumentation掌控。**(ActivityThread.LoadedApk.makeApplication 方法中)
231 |
232 | BONUS:另外我们还顺带发现了另外一个问题的答案:**主线程的 Looper 是什么时候实例化的?**
233 |
234 | 答案显而易见: ActivityThread.main 。
235 |
236 | ActivityThread 非常重要,它更是我们常说的`mainThread`!后续还会讲更多关于它的知识。
237 |
238 | ## See Also
239 |
240 | 我在知乎上的提问:[Android 应用的真正入口是哪里?](https://www.zhihu.com/question/50828920)
241 |
242 |
243 |
--------------------------------------------------------------------------------