├── 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 | ![效果图](http://ww2.sinaimg.cn/large/98900c07jw1f6pxwz67aqg207l0ckq30.gif) 37 | 38 | 是不是很闪? 39 | 40 | 明明这么闪耀,为何要躲起来? 41 | 42 | `BlinkLayout`的使用也有些特殊,它跟`merge`、`include`这些标签一样,用标签`blink`来表示。 43 | 44 | 贴一下上图效果的XML: 45 | 46 | ``` 47 | 51 | 52 | 57 | 58 | 59 | 63 | 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 | ![流程图](http://ww4.sinaimg.cn/large/98900c07jw1f6ul65ibh3j20g40qeta0.jpg) 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 constructor = sConstructorMap.get(name); 394 | Class 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 | ![我的微信](http://ww3.sinaimg.cn/thumbnail/98900c07gw1f2f30b7cs5j20e80e80tx.jpg) 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 | ![Space使用场景](http://ww2.sinaimg.cn/large/98900c07jw1f6pifwudkgj201k0110mp.jpg) 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> 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 | --------------------------------------------------------------------------------