-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
207 lines (134 loc) · 92.4 KB
/
atom.xml
File metadata and controls
207 lines (134 loc) · 92.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>tom的闲言碎语</title>
<subtitle>既可朝九晚五,又能浪迹天涯</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://lightom.cc/"/>
<updated>2017-06-30T09:25:44.000Z</updated>
<id>http://lightom.cc/</id>
<author>
<name>tom</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>安卓App稳定性之旅--记Crash率 <=0.1% 实践</title>
<link href="http://lightom.cc/2017/06/30/app-crash/"/>
<id>http://lightom.cc/2017/06/30/app-crash/</id>
<published>2017-06-30T09:22:54.000Z</published>
<updated>2017-06-30T09:25:44.000Z</updated>
<content type="html"><![CDATA[<h2 id="稳定性的意义"><a href="#稳定性的意义" class="headerlink" title="稳定性的意义"></a>稳定性的意义</h2><p>在移动应用性能方面,崩溃带来的影响是最为严重的。</p><p>移动应用崩溃主要是由操作系统引发,是指应用在运行过程中出现的强制关闭(Force Closing)现象,从而<strong>打断用户正在进行的操作体验</strong>。</p><p>应用崩溃可以造成关键业务中断、用户留存率下降、品牌口碑变差、生命周期价值下降等影响。</p><p>根据统计数据显示,当iOS的崩溃率超过0.8%,Android的崩溃率超过0.4%的时候,<strong>活跃用户有明显下降态势</strong>。</p><a id="more"></a><h2 id="行业标准"><a href="#行业标准" class="headerlink" title="行业标准"></a>行业标准</h2><p><img src="http://note.youdao.com/yws/api/personal/file/WEBcc64e9363f64d985f70ca7780f050d79?method=download&shareKey=be787dc8894f561b5b893f37a58523f1" alt="image"></p><p>Android行业标准:</p><ul><li>优秀App:0%-0.2%</li><li>标准App:0.2%-0.4%</li></ul><p>而作为一个有追求的技术团队,我们追求一个有挑战的标准:<strong>Crash Session<=0.1%</strong> 或者说<strong>Crash Free Session>=99.9%</strong></p><p>:)</p><h2 id="改进前"><a href="#改进前" class="headerlink" title="改进前"></a>改进前</h2><p><img src="http://note.youdao.com/yws/api/personal/file/WEBf1cddb3b83dc5bf4572e26b0a1d5af42?method=download&shareKey=6bf0a9a43857f91805c4a6d278c8a773" alt="image"></p><p>分析:</p><ul><li>Crash平均在0.3%</li><li>偶尔触达0.2%</li><li>某时间段一度高于0.8%(不稳定)</li><li>从未达到过0.1%</li></ul><p>评价:处于行业<strong>标准水平</strong>,偶尔有隐患版本发布</p><h2 id="三板斧"><a href="#三板斧" class="headerlink" title="三板斧"></a>三板斧</h2><ol><li><p>磨刀不误砍柴工:<strong>改进Crash上报系统</strong></p><p> 每个app都有Crash上报系统,手机证券采用的是百度SDK。而它不能将线上混淆后的代码映射成开发代码,因此很难定位问题。</p><p> 因此我们将百度SDK替换成Fabric。</p><p> <strong>百度SDK:</strong></p><p> <img src="http://note.youdao.com/yws/api/personal/file/WEBa60ce6119597963e51236f20fde798e8?method=download&shareKey=a99cc3ebb50c3d8d1f1eaf624d613441" alt="image"></p><p> <strong>Fabric:</strong></p><p> <img src="http://note.youdao.com/yws/api/personal/file/WEB58122efe362532c7cb71cf301cf5a9cc?method=download&shareKey=9af5e900d350cc416c0391014388bb4c" alt="image"></p></li><li><p>第一板斧:<strong>解决Crash问题</strong></p><p> 现在的当务之急当然是解决已有Crash问题了。</p><p> <img src="http://note.youdao.com/yws/api/personal/file/WEBfa9c50014addfa509e1f0dcf0eb39c09?method=download&shareKey=6fa779722ab01350532c1c69f7a7c813" alt="image"></p></li><li><p>第二板斧:<strong>提高编码质量</strong></p><p> 高质量代码是稳定性的基石,在当前背景下(较多需求开发),我们有没有工具能高效地帮助我们提高代码质量呢?,能有立竿见影效果呢?</p><p> 静态扫描工具:<strong>Lint、Findbugs</strong></p><ul><li><p>Lint:安卓自带的代码扫描工具</p><p> 通过它对Android工程源代码进行扫描和检查,可发现潜在的问题。</p><p> 主要包括:xml文件中是否存在hardcode、unused resources、probable bug等等。</p></li><li><p>Findbugs是java的静态分析工具</p><p> 它检查类或者JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。</p><p> Findbugs自带检测器,其中有60余种Bad practice,80余种Correctness,1种 Internationalization,12种Malicious code vulnerability,27种Multithreaded correctness,23种Performance,43种Dodgy。</p><p>通过这两个工具的扫描报告,可以找到很多代码的逻辑错误、隐藏问题、性能问题等一般共性问题。</p><p>同时我们也要认识到这类工具的局限性。并通过自定义配置来避免“噪音”。</p><p><strong>lint:</strong></p><p><img src="http://note.youdao.com/yws/api/personal/file/WEB9c22cbfb40a568b916ea258117c0140f?method=download&shareKey=9f3a2b88fa71ceefc272115bf22ed6ae" alt="image"></p><p><img src="http://note.youdao.com/yws/api/personal/file/WEB101924f1bfb7ccc13ce60ed40668a997?method=download&shareKey=8ceaddfc025d94f3435a8eab104c47d5" alt="image"></p><p><strong>findbugs:</strong></p><p><img src="http://note.youdao.com/yws/api/personal/file/WEBb73094bf41894994d06404c19fa85686?method=download&shareKey=2c84acec973e684643bc504f96165389" alt="image"></p><p><img src="http://note.youdao.com/yws/api/personal/file/WEB3e479ac09f87d7ea64bc05f14fcd0338?method=download&shareKey=ae3c0ea97a59b8df3d952b41e29291c3" alt="image"></p></li></ul></li><li><p>第三板斧:<strong>灰度</strong></p><p> 测试遗漏问题就这样放出去吗?有隐藏bug怎么办?</p><p> 祭出王牌:<strong>灰度发布</strong></p><p> 所谓的灰度发布,简单来讲,就是不要一开始就让所有用户下载安装应用,而是先覆盖一小部分用户!</p><p> 发布不是简单的从0到1,不是非黑即白,在中间有一个缓冲的<strong>灰色地带</strong>。</p><p> 通过灰度发布,真实用户的真实场景测试,我们可以更全面、更深入的收集问题,修复问题。<br> 随着灰度覆盖范围的增加,暴露的问题也越来越充分,而当全量发布的时候,一定是一个稳定的版本!</p><p> 目前的策略:先在某一个渠道灰度,当问题暴露的足够多时,再发布全量版本。</p></li></ol><h2 id="改进后"><a href="#改进后" class="headerlink" title="改进后"></a>改进后</h2><p><img src="http://note.youdao.com/yws/api/personal/file/WEB4e91928c6809c2b0cb92262d2edf8d1b?method=download&shareKey=f654fcd4535bc1d511f4cfb87f17e09b" alt="image"></p><h2 id="Never-Stop"><a href="#Never-Stop" class="headerlink" title="Never Stop"></a>Never Stop</h2><h3 id="目标:长期稳定在-lt-0-1"><a href="#目标:长期稳定在-lt-0-1" class="headerlink" title="目标:长期稳定在<=0.1%"></a>目标:长期稳定在<=0.1%</h3><h3 id="后续规划的实践"><a href="#后续规划的实践" class="headerlink" title="后续规划的实践"></a>后续规划的实践</h3><ol><li><p>编程维度:</p><ul><li><p>持续解决收集到的Crash问题</p></li><li><p>OOM和内存泄漏问题:</p><ul><li>通过LeakCancary来检测内存泄漏问题,并解决问题。</li><li>通过内存检测工具来检测内存占用情况,并优化问题。</li><li>通过技术选型,寻找更好的图片管理框架。</li></ul></li><li><p>编码规范:编码规范的重要性我就不阐述了</p><ol><li>统一团队内编码规范,这里可以参考:<a href="http://suo.im/43uTk5" target="_blank" rel="noopener">阿里巴巴的Java开发手册</a>,站在巨人的肩膀上。</li><li>生成编码规范的IDE(Android Studio)配置,工程师导入配置之后,可以非常方便的用快捷键 Reformate Code</li><li>使用静态扫描工具CheckStyle和Lint来检查代码规范。</li></ol></li><li><p>代码重复度:</p><ol><li>通过静态扫描工具检测重复代码。</li><li>抽取重复代码,提供工具类及底层基础类。</li></ol></li><li><p>复杂度:</p><ul><li>框架升级:一个好的框架可以减少工程师的代码量,提高效率。</li><li>Kotlin:语言级的改进。简洁的语法,以及NullSafty特性都是非常好的特性。</li></ul></li></ul></li><li><p>流程化及工具维度:</p><ul><li>结对编程:主要是在前期设计和疑难模块编写时使用,希望取长补短,寻求更高质量的代码。</li><li>CodeReview:在代码提交的流程上使用CodeReview机制。</li><li>在Jenkins中集成静态扫描插件:findbug、lint、CheckStyle、PMD等。</li></ul></li><li><p>测试维度:</p><ul><li>充分的开发自测:自己写的代码,自己最清楚会有什么问题,开发自测发现问题的效率最高。</li><li>单元测试:<ul><li>引入单元测试框架:junit、mockito、robolectric</li><li>静态扫描工具:单元测试覆盖率</li></ul></li><li>兼容性测试</li><li>monkey测试</li></ul></li><li><p>发布维度:</p><ul><li><p>灰度2.0</p><p> 当前灰度策略其实还不完善,后续我们会提供一种更完善的灰度机制:根据用户的应用版本号,手机型号,UUID等信息来选择灰度的用户,通过弹对话框的方式提示用户升级。</p><p> 这样我们就能很方便的从多个维度来灰度,比如:Android7.0里面5%的用户。</p></li><li><p>终极杀招:<strong>热修复</strong></p><p> 通过热修复技术,客户端可以发布补丁来解决线上版本的稳定性问题,而无需发版本。</p><p> 热修复作为当下热门的技术,在业界内比较著名的有阿里巴巴的AndFix、Dexposed,腾讯QQ空间的超级补丁和微信的Tinker。</p></li></ul></li></ol>]]></content>
<summary type="html">
<h2 id="稳定性的意义"><a href="#稳定性的意义" class="headerlink" title="稳定性的意义"></a>稳定性的意义</h2><p>在移动应用性能方面,崩溃带来的影响是最为严重的。</p>
<p>移动应用崩溃主要是由操作系统引发,是指应用在运行过程中出现的强制关闭(Force Closing)现象,从而<strong>打断用户正在进行的操作体验</strong>。</p>
<p>应用崩溃可以造成关键业务中断、用户留存率下降、品牌口碑变差、生命周期价值下降等影响。</p>
<p>根据统计数据显示,当iOS的崩溃率超过0.8%,Android的崩溃率超过0.4%的时候,<strong>活跃用户有明显下降态势</strong>。</p>
</summary>
<category term="技术" scheme="http://lightom.cc/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Android" scheme="http://lightom.cc/tags/Android/"/>
</entry>
<entry>
<title>关于要不要买房的随想</title>
<link href="http://lightom.cc/2017/05/25/maifang/"/>
<id>http://lightom.cc/2017/05/25/maifang/</id>
<published>2017-05-25T10:38:12.000Z</published>
<updated>2017-06-30T09:33:28.000Z</updated>
<content type="html"><![CDATA[<p>关于买房,tom在这里谈一下自己的理解。希望以上对你有帮助,特别是在纠结要不要买房的你。</p><h3 id="房子的几个属性:"><a href="#房子的几个属性:" class="headerlink" title="房子的几个属性:"></a>房子的几个属性:</h3><a id="more"></a><ol><li><p>居住属性</p><p> 房子最基本属性就是居住属性了,遮风挡雨,门朝大海。</p><p> 对此,有人不削一顾:我也可以租房呀,租房的钱比买房的钱少多了,何必要买房,每个月被着债,承受这么大压力,给银行打工。我为什么要贷款30年,让自己变成房奴,失去自由?</p><p> 听起来确实是事实。</p><p> 但是另一方面呢,tom想提醒一下,如果能认真计算的话,我们需要把时间拉长一点,不要只考虑眼前的情况。我们要考虑到的一点是:月供不会涨(其实月供每年随利息调整,导致月供变多或者变少),租金可是随市场行情变动的。特别是在一线城市,如果每年人口都是净流入,如果工作日八点上班挤地铁的人没有少。你是否对房租上涨有预期?</p><p> 举一个例子,四年前,深圳某小区一个业主,购买了一套房,交房后立马装修,以最快的速度租出去了,由于是新房,精装修,而房租已经能抵月供了。未来涨房租在深圳也是大概率事件。</p></li><li><p>心理属性</p><p> 特别是在大城市打工的飘飘族,能有一套房子,内心的状态是不一样的,有一种不在漂泊的安定感。</p><p> 买房后不会考虑搬家了,有多少人是忍受不了搬家而买房的?举个手。</p><p> 买房对于打动丈母娘有效。</p><p> 举个例子:</p><p> 小A和小B是同班同学,11年毕业一起进入鹅厂工作,小A是个很有追求的人,每天加班加点,在工作上的成绩很高,3年之后,小A升上了T3,成为了高级工程师,得到了领导的表扬。小B呢,现在还在普通工程师级别。</p><p> 小B性格开朗,平时喜欢玩,13年的时候由于不想反复搬家,用自己的存款和部分父母的赞助,在深圳招商某小区购入80多平的三房,现在该套房产价值500多万。小B平时不愿意坐地铁挤公交,于是花钱买了辆车代步,在滴滴顺风车上认识了同在鹅厂做产品经理的妹子小C。两人情头意合,由于小B深圳的房产,让丈母娘觉得可以放心把女儿托付给他,获得了丈母娘的肯定,原来小C也在招商某小区有一套房产,现在两人结合,一个千万资产的家庭即将诞生。</p><p> 小A由于一心投入在事业上,等到要成家买房的时候,发现房价已经很高了,15年底,花光了积蓄才买到一个小两房,但是看到未婚妻在家里布置打扫,也感觉到了家的温暖。</p></li><li><p>投资属性</p><p> 很多人都有一个误区,觉得买房就是用来住的,我不住干嘛要买房?此时,有人应该忘记了房子的另一个属性:投资属性。</p><p> 房子的收益包括租金和房价上涨带来的利得。房产和股票、和你买的理财产品,都是一样有投资价值的。</p></li><li><p>金融杠杆属性</p><p> 杠杆是什么?以小博大。100块钱价值的房子,花30块钱的首付就可以拥有。首付30%,就是3.33倍的杠杆。</p><p> 举一个例子:小王13年以30%的首付,2w的单价,在深圳购入一套100平房产,16年的时候,房价涨到了6w一平。</p><p> 我们来算算账:</p><p> 投入:60w的首付款 + 3年的房贷28w(每月持续投入) = 88w</p><p> 收益:600w的房产 - 110w剩余房贷 = 490w</p><p> 这就是杠杆的力量。同时大家也要看到杠杆的危险性,每个月都要背负月供。3年房贷就有28w了。人性相比收益,更不能承受损失,当你用杠杆的时候,需要问下自己,是否能承受房价下跌?房价下跌是否会影响自己的生活?</p></li><li><p>总结</p><p> 以上是我对房子的4个属性的认知,有很多细节都还没说。回想起tom当初买房时候的认知,只是认识到第二个属性,单纯的想要在大城市有份安定感。</p><p> 我发现,对买房的认知越高,特别是有第三和第四个认知的人,就越有钱。几个认识的邻居和朋友,早几年的时候已经有投资意识,他们对大环境有清晰的认识,对投资有明确的规划。用金融杠杆来投资房产。按照我的生活标准,现在已经财务自由了。</p></li></ol><h3 id="给我一个不买房的理由"><a href="#给我一个不买房的理由" class="headerlink" title="给我一个不买房的理由"></a>给我一个不买房的理由</h3><p>看到这里,你告诉我,这几个认知我都明白。但是,经过仔细考虑,我觉得现在的房地产市场风险太高,房子流动性风险太大,我的其他投资渠道性价比(收益和风险比)更高。未来从资产配置角度考虑,也会考虑房产,但是不是现在。</p><p>这个时候,基于我自己的认知,我也是非常同意你的看法的。:)</p><p>也许未来对买房会有新的认知,而且新的认知会告诉你之前都做错了,但是那有怎样?</p><p>基于现有的认知,去了解,去实践,在自己的能力范围内,基于实践反复迭代自己的认知。让自己的认知最终指导你做出选择。然后告诉自己,就算最后证明自己做错了,也是自己经过自己独立思考后的选择。</p><p>而不是偏听自己喜欢的观点,谁唱空房价就传颂,谁唱多房价就骂谁。</p><h3 id="写在最后的"><a href="#写在最后的" class="headerlink" title="写在最后的"></a>写在最后的</h3><p>买房已经成为十足的热点话题,特别是北上广深一线城市,房价已经貌似突破天际,从我有印象开始,媒体每年骂房价,说辞都是一样的,不吃不喝100年才能买得起房。</p><p>媒体喜欢报到也许是因为大家爱看吧。但这不是事实的全部。</p><p>重要的是,我们自己对房子有自己的认知,并且愿意投入时间去思考,在能力范围内去实践。毕竟,这是跟我们生活息息相关的重要事情。</p><p>看到这里,买不买房,你是不是有自己的看法了?:)</p><p>tom不预测房价,只是在讲述对这几年买房的随想。投资有风险,投资需谨慎。</p>]]></content>
<summary type="html">
<p>关于买房,tom在这里谈一下自己的理解。希望以上对你有帮助,特别是在纠结要不要买房的你。</p>
<h3 id="房子的几个属性:"><a href="#房子的几个属性:" class="headerlink" title="房子的几个属性:"></a>房子的几个属性:</h3>
</summary>
<category term="生活" scheme="http://lightom.cc/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="投资理财" scheme="http://lightom.cc/tags/%E6%8A%95%E8%B5%84%E7%90%86%E8%B4%A2/"/>
<category term="买房" scheme="http://lightom.cc/tags/%E4%B9%B0%E6%88%BF/"/>
</entry>
<entry>
<title>云校园Android客户端技术演进之路</title>
<link href="http://lightom.cc/2016/09/09/yxy-tech-upgrade/"/>
<id>http://lightom.cc/2016/09/09/yxy-tech-upgrade/</id>
<published>2016-09-09T02:30:20.000Z</published>
<updated>2017-06-30T09:33:29.000Z</updated>
<content type="html"><![CDATA[<p>打个广告:<strong>云校园是什么?</strong></p><p><a href="http://www.yunxiaoyuan.com/" target="_blank" rel="noopener">云校园</a>,作为拓维教育云平台中主打7-18岁教育阶段的一款教育产品,围绕学校、老师、家长、学生四个角色,打造精细化教学管理及校园高价值信息收集分发平台,同时运用本地化家长社区为家长提供海量教育资讯,并为学生提供具有丰富优质学习资源的个性化学习空间,合力构建K12家校共育平台。</p><p><img src="/2016/09/09/yxy-tech-upgrade/yxy.jpg" alt=""></p><p>云校园经历了2年的发展,从最初1.0到现在的5.0版本。App包含功能插件、家校互通、社区、资讯、学习资源、支付、推送、统计等各种功能和模块。</p><p>客户端的技术架构也随业务发展演进到现在。让我们开始吧。</p><a id="more"></a><h2 id="技术选型"><a href="#技术选型" class="headerlink" title="技术选型"></a>技术选型</h2><p>1、<strong>通用框架</strong><br>搭建云校园1.0的时候,从零起步,安卓开发只有2人,为了提高开发效率,我们想选一个通用的安卓开发框架。</p><p>当时较好的框架有AFinal、XUtils等。</p><p>我们最后选择了XUtils,因为XUtils基于AFinal,包含了很多实用工具,稳定性也提高了不少。</p><p>XUtils主要包括4大模块:</p><ul><li>DbUtils:提供了对象关系映射(ORM)数据库的功能,可以方便的进行对象存储</li><li>ViewUtils:通过注解方式进行UI,资源和事件绑定。可以减少代码量,较少的代码量意味着更少的Bug和更高的开发效率</li><li>HttpUtils:封装了网络请求模块,相比系统组件HttpClient和HttpUrlConnection更好用</li><li>BitmapUtils:较好的图片加载模块,对图片下载和存储统一管理</li></ul><p>在云校园最开始,XUtils确实发挥了较好的作用,提高了开发效率。这个框架的特点是,功能很全。这是它的优点,同时也是它的缺点。就好像什么都做,但是什么都做不好一样。</p><p>所以,我们后来引入了其他的框架替代了XUtils。DB模块被ormLite替代,View模块被Butterknife替代,Http被Volley替代,Bitmap模块被ImageLoader替代。替换上的每个框架都是该领域的佼佼者,更好更专业的完成了各自领域的工作。</p><p>2、<strong>ORM框架</strong><br>ORM的英文是Object Relation Mapping,也就是对象关系映射,它是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。</p><p>我举一个直观的例子,存储一个Book对象到数据库:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Book book = new Book("good");</span><br><span class="line">book.setIndex(1988);</span><br><span class="line">book.setAuthor("hehe");</span><br><span class="line">liteOrm.save(book);</span><br></pre></td></tr></table></figure></p><p>优点:隐藏了数据访问的细节,将通用数据库的操作封装起来,程序员不用写SQL语句,能把更多的精力放到业务逻辑上去。同时ORM跟具体数据库解耦,也能很方便的替换数据库。<br>缺点:牺牲了性能,也不能做SQL优化,有一定的学习成本,而且处理复杂的查询力不从心。</p><p>ORM框架已经有很多了,比如OrmLite、SugarORM、GreenDAO、Realm。<br>OrmLite是Java的Orm框架,Android当然能用了。<br>SugarORM是Android平台专用框架,提供简单易学的API,上手很快。<br>GreenDAO适用于对性能要求高情况,而且SDK包不到100K。<br>Realm是一个跨平台、高性能的框架,支持IOS。</p><p>最后我们选择了老牌的OrmLite,考虑的是集成方便,上手快,而且稳定性不错。现在Ormlite一直沿用至今,反响不错。</p><p>3、<strong>依赖注入框架</strong><br>DI(依赖注入)其实是一种设计模式,现在已经被频繁的应用到安卓开发中。<br>它能够让开发者编写出低耦合的代码,而且更容易测试。</p><p>我们首先看看依赖注入的直观感受:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">class ExampleActivity extends Activity {</span><br><span class="line"> </span><br><span class="line"> @BindView(R.id.user) EditText username;</span><br><span class="line"> @BindView(R.id.pass) EditText password;</span><br><span class="line"> @BindString(R.string.login_error) String loginErrorMessage;</span><br><span class="line"> </span><br><span class="line"> @OnClick(R.id.submit) void submit() {</span><br><span class="line"> // TODO call server...</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override public void onCreate(Bundle savedInstanceState) {</span><br><span class="line"> super.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.simple_activity);</span><br><span class="line"> ButterKnife.bind(this);</span><br><span class="line"> // TODO Use fields...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>云校园的依赖注入框架由最开始的XUtils,换成了AndroidAnnotations,最后又替换成ButterKnife和Dagger2。</p><p>Butterknife针对Android平台,提供了View,资源,事件回调等注入。非常方便、易懂。<br>而Dagger2可以注入各种组件,配合Activity生命周期管理组件生命周期。是MVP模式(后面会讲)的天然搭档。<br>基于这两款框架,我们降低了20%的代码量,而且代码的耦合性很低。</p><p>4、<strong>网络模块框架</strong><br>网络模块必不可少。</p><p>Android系统提供了HttpClient和HttpUrlConnection。HttpClient是Apache的开源实现,而HttpUrlConnection是Android2.2之后的标准实现,而且是官方推荐的。虽然HttpUrlConnection做了不少封装但是还是不好用。</p><p>随着Android的流行,出现了很多优秀的网络模块框架。<br>比如:android-async-http、Okhttp、Retrofit、Volley。</p><p>Retrofit提供了非常好的RESTful封装和解耦,而且支持rx编程。</p><p>async-http能很好的完成了网络的异步请求与回调,而且HTTP请求发生在UI线程之外。</p><p>但是Volley对网络的封装得很好。<br>我们采用Volley,通过自定义Request,我们用面向对象的方式封装了各个网络请求业务。<br>BaseRequest进行统一的公共的参数处理、错误处理、公共的返回处理。<br>外部请求传入较少的参数,只需要考虑业务逻辑。</p><p>引入Volley之初,Volley的底层使用的是Android系统组件:HttpClient+HttpURLConnection,后来发现,OkHttp使用NIO更加高效,于是我们也将Volley的底层切换为OkHttp。</p><p>对于协议层,我们没有采用Json,而是用的Thrift。<br>Thrift作为跨语言RPC框架有很多优点,相比json,序列化之后的传输小了不少,而且安全性更高。<br>另外Thrift还有一个很好的特点:协议结构清晰,而且有很好的扩展性。</p><p>5、<strong>图片加载框架</strong><br>云校园有大量的图片显示需求,而图片这块涉及到下载,缓存,异步加载,图片处理,OOM等问题。特别是OOM这块,图片占用了应用大量内存,如果内存管理不好,很容易出现内存溢出,导致应用稳定性问题。</p><p>云校园的图片加载框架从早期的XUtils切换到ImageLoader,满足了基本的需求。但是ImageLoader的作者已经不再维护这个框架了。我们开始调研新的图片加载框架。</p><p>Picasso比较轻量,但是Glide的默认参数配置更好。</p><p>因为每个图片加载框架的区别很大,为了防止迁移和切换带来很大的工作量,我们提取了自己的图片加载组件ImageManager,作为图片加载框架的适配器。保证了这块的解耦。</p><p>Fresco在4.4及以下版本使用匿名内存来作为内存缓存,能极大的减少OOM。但是缺点是包很大。</p><p>综合考虑后,我们选择了Google官方的Glide加载框架。</p><h2 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h2><p>1、<strong>解耦</strong><br>问题:在Activity及各个组件之间进行事件传递,大家会用什么方式?<br>Intent?Handler?BroadCastReceiver?Callback?<br>这些都不是好的解决方案。<br>EventBus却用一种优雅的方式,一种松耦合的方式解决这个问题。</p><p>我们看一个直观的例子:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">//A组件内发送事件</span><br><span class="line">eventBus.post(new AnyEventType());</span><br><span class="line"></span><br><span class="line">//B组件内接受事件</span><br><span class="line">@Subscribe </span><br><span class="line">public void onEvent(AnyEventType event) {/* Do something */};</span><br></pre></td></tr></table></figure></p><p>怎么样?是不是迫不及待的想用起来,解决项目里面无处不在的Handler传递?<br>引入EventBus后,每个组件之间的耦合性降低了很多,统一的事件分发管理也让业务逻辑清晰简单。</p><p>2、<strong>架构模式MVP</strong><br>MVP模式相比传统的MVC模式,一般大家普遍的认识都是:“MVC的演化版本”、“让Model和View完全解耦”、“代码很清晰,不过增加了很多类”。</p><p>MVP模式的一个核心点是Model和View不会直接交互,而是由Presenter完成。</p><p><img src="/2016/09/09/yxy-tech-upgrade/mvp.jpg" alt=""></p><p>我们在项目中引入MVP模式的一个主要原因是:Activity既当View,又当Controller,导致Activity内部代码庞大,而引入MVP后,Activity只作为View,Controller负责的业务逻辑被封装到了Presenter里面,代码更为清晰。</p><p>在项目中,复杂的需求我们会优先采用MVP模式。</p><p>3、<strong>响应式编程(RX)</strong><br>响应式编程是一种面向数据流和变化传播的编程方式。<br>利用响应式编程,我们可以加深代码抽象的程度,可以很好的解决Callback Hell的问题,而且在线程切换问题上易如反掌。</p><p>给大家一个直观的例子:</p><p>假设有这样一个需求:<br>界面上有一个自定义的视图imageCollectorView,它的作用是显示多张图片。现在需要程序将一个目录中每个目录下的png图片都加载出来并显示在imageCollectorView中。<br>你会怎么做?(注意:由于读取图片的程较为耗时,需要放在后台线程执行,而图片的显示则必须在UI线程执行。)</p><p>通常做法(Callback Hell):<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">new Thread() {</span><br><span class="line"> @Override</span><br><span class="line"> public void run() {</span><br><span class="line"> super.run();</span><br><span class="line"> for (File folder : folders) {</span><br><span class="line"> File[] files = folder.listFiles();</span><br><span class="line"> for (File file : files) {</span><br><span class="line"> if (file.getName().endsWith(".png")) {</span><br><span class="line"> final Bitmap bitmap = getBitmapFromFile(file);</span><br><span class="line"> getActivity().runOnUiThread(new Runnable() {</span><br><span class="line"> @Override</span><br><span class="line"> public void run() {</span><br><span class="line"> imageCollectorView.addImage(bitmap);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }}.start();</span><br></pre></td></tr></table></figure></p><p>RX做法:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Observable.from(folders)</span><br><span class="line"> .flatMap((Func1) (folder) -> { Observable.from(file.listFiles()) })</span><br><span class="line"> .filter((Func1) (file) -> { file.getName().endsWith(".png") })</span><br><span class="line"> .map((Func1) (file) -> { getBitmapFromFile(file) })</span><br><span class="line"> .subscribeOn(Schedulers.io())</span><br><span class="line"> .observeOn(AndroidSchedulers.mainThread())</span><br><span class="line"> .subscribe((Action1) (bitmap) -> { imageCollectorView.addImage(bitmap) });</span><br></pre></td></tr></table></figure></p><p>基于事件流,已经没有烦人的回调嵌套了,每一步业务逻辑都非常清晰:读目录->读PNG文件->转成Bitmap->显示图片。</p><p>这样的代码,真是让bug无处藏身呀!!!</p><p>而且Rx有很多周边组件可以用,比如rxlifecycle,把Activity生命周期和Rx事件流绑定,当Activity销毁的时候,可以自动解绑事件流。避免了内存泄漏。</p><h2 id="开发者服务"><a href="#开发者服务" class="headerlink" title="开发者服务"></a>开发者服务</h2><p>现在的移动应用开发环境已经很成熟了,有很多不错的开发者服务能够帮助开发者快速开发。</p><p>比如:</p><ul><li>应用统计:友盟统计、fabric</li><li>推送:信鸽、个推</li><li>IM:腾讯云、环信</li><li>分享:ShareSDK、友盟分享</li><li>Crash上报:Crashlytics、Bugly、BugTags</li><li>云存储:阿里OSS、七牛云存储</li><li>自动更新:友盟更新、讯飞</li><li>用户反馈:友盟反馈</li><li>应用分发:蒲公英、fir.im</li></ul><p>基于这些基础服务,开发者可以把主要精力放在业务逻辑上,做到快速开发。</p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>1、<strong>统一Style和主题</strong></p><p>我们发现在写UI界面的时候,每个View控件为了做到高质量的UI还原,需要为每个控件写很多属性。而且很多属性不停的重复。</p><p>写代码最基本的几个原则是要避免重复代码,如果出现超过2次,就应该提取。</p><p>所以针对上述情况,我们针对每种控件,抽取出公共的style属性来。</p><p>在写界面的时候,直接使用:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><TextView</span><br><span class="line"> android:id="@+id/title_textview"</span><br><span class="line"> style="@style/Text.Title"</span><br><span class="line"> android:text="@string/no_login_tip_title"</span><br><span class="line"> /></span><br></pre></td></tr></table></figure><p>这样做的好处是:</p><ul><li>代码量少</li><li>调整UI非常方便,且很容易做主题</li><li>形成了一整套风格统一的UI,<strong>规范了程序员和设计师</strong></li></ul><p>2、<strong>工具类</strong></p><p>很多有用的工具可以帮助程序员。</p><ul><li><p>leakcanary,用来查应用的内存泄漏<br><img src="/2016/09/09/yxy-tech-upgrade/leakcanary.png" alt=""></p></li><li><p>facebook出品的stetho,用来调试Android应用。包括:查看App的布局,网络请求,sqlite,preference,一切都是可视化的操作。<br><img src="/2016/09/09/yxy-tech-upgrade/stecho.jpg" alt=""></p></li><li><p>持续集成<br>应用的持续集成,自动化的发布版本,能更敏捷的让产品经理体验需求。而Jenkins无疑是首选。<br>Jenkins是免费的持续集成工具,云校园利用Jenkins,定时拉取代码,编译,打包,并上传到分发平台-蒲公英,并发送邮件。非常完美的完成了持续集成的工作。<br><img src="/2016/09/09/yxy-tech-upgrade/jenkins.png" alt=""></p></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Android的开发环境越来越成熟,作为一个开发者,我们不能故步自封,要跟随着发展趋势,站在“巨人”的肩膀上,最大限度的利用新技术和服务,应用到项目中,解决实际问题。</p><p>要记住,能偷懒的程序员,才是好程序员。</p>]]></content>
<summary type="html">
<p>打个广告:<strong>云校园是什么?</strong></p>
<p><a href="http://www.yunxiaoyuan.com/" target="_blank" rel="noopener">云校园</a>,作为拓维教育云平台中主打7-18岁教育阶段的一款教育产品,围绕学校、老师、家长、学生四个角色,打造精细化教学管理及校园高价值信息收集分发平台,同时运用本地化家长社区为家长提供海量教育资讯,并为学生提供具有丰富优质学习资源的个性化学习空间,合力构建K12家校共育平台。</p>
<p><img src="/2016/09/09/yxy-tech-upgrade/yxy.jpg" alt=""></p>
<p>云校园经历了2年的发展,从最初1.0到现在的5.0版本。App包含功能插件、家校互通、社区、资讯、学习资源、支付、推送、统计等各种功能和模块。</p>
<p>客户端的技术架构也随业务发展演进到现在。让我们开始吧。</p>
</summary>
<category term="技术" scheme="http://lightom.cc/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Android" scheme="http://lightom.cc/tags/Android/"/>
<category term="稳定性" scheme="http://lightom.cc/tags/%E7%A8%B3%E5%AE%9A%E6%80%A7/"/>
</entry>
<entry>
<title>Android简史</title>
<link href="http://lightom.cc/2016/07/12/android-story/"/>
<id>http://lightom.cc/2016/07/12/android-story/</id>
<published>2016-07-12T02:08:43.000Z</published>
<updated>2017-06-30T09:33:39.000Z</updated>
<content type="html"><![CDATA[<p>懒癌发作好久没更新了,最近得空想放个大招,写写自己的老本行,天马行空的介绍下安卓的发展历程和历史。</p><p>总结下,我想讲如下几个方面:</p><ul><li>Android之父</li><li>Google为什么收购Android</li><li>发展历程</li><li>Android为什么会火</li><li>免费的怎么赚钱</li><li>专利战</li><li>历史版本</li><li>关于抄袭</li><li>架构</li><li>技术发展现状</li><li>趋势</li></ul><p>好像一下写太多,有些题目又太大了。–!</p><a id="more"></a><h2 id="Android之父"><a href="#Android之父" class="headerlink" title="Android之父"></a>Android之父</h2><p>Andy Rubin<br><img src="http://static.leiphone.com/uploads/new/article/600_600/201410/54536909a2606.jpg?imageMogr2/format/jpg/quality/80" alt="img"></p><p>Andy是一个典型的Geek,1963年出生于美国纽约,在他53年的极客人生中,他一直致力于将最酷、最超越时代的电子产品呈现给世人。<br>从网络电视,到数码相机,到智能手机,到各式机器人,从苹果到微软再到现在的谷歌,鲁宾总是在最酷的公司做着最酷的研究。</p><p>Andy先后在卡尔·蔡司、苹果、微软等知名公司工作,后来成立了Danger和Android两家公司。</p><p>担任Danger公司CEO期间,由于运营不理想,被迫辞职。随后,Andy跑到自己的老度假福地开曼群岛待了几个月,并在那里开始编写软件,试图研制一款数码相机的操作系统。但老问题又来了,没人肯投资这款相机。兜兜转转,Andy又回到了研制智能手机操作系统上。</p><p>Andy把所有的积蓄都倾注在Android项目上。但还是遇到了缺钱的问题。很快,有风险资本家对Android的开发项目感兴趣,提出收购Android。但是Andy主动跟Google创始人Page发邮件,暗示Android也存在跟谷歌合作的可能性。</p><p>几周后,也就是2005年8月,Google以五千万美元的价格收购了名不见经传的Android。Andy成为谷歌公司的工程部副总裁,继续负责Android项目。</p><h2 id="Google为什么收购Android?"><a href="#Google为什么收购Android?" class="headerlink" title="Google为什么收购Android?"></a>Google为什么收购Android?</h2><p>战略收购。</p><p>Google擅长于网络,但是在移动端硬件和操作系统的积累较少。Google似乎预感到移动互联网的趋势,为了抢夺移动终端入口,收购了Android。</p><p>原因:Android系统中可以无缝整合谷歌的各种服务和软件,加上开源带来的各种应用的丰富、繁荣,谷歌可以与应用开发者合作,借助谷歌的广告技术让大家实现共赢,形成良好的生态圈。</p><p><img src="http://images.cnitblog.com/i/413416/201405/132108156409332.png" alt=""></p><center><strong>互联网设备份额</strong></center><p>此时天时地利,郎有情妾有意,Andy发给Page的邮件无意间促成了收购,这笔收购在现在看来,堪称Google最成功的收购。</p><h2 id="发展历程"><a href="#发展历程" class="headerlink" title="发展历程"></a>发展历程</h2><p>Android在2005年被收购之后,花完了资金,陷入不温不火的尴尬境地。</p><p>正当Andy为未来悲观时,苹果拯救了Android。- -!,是的,你没有看错。<br>2007年,乔布斯发布第一款iPhone。全新的理念和无比友好的界面,立即震撼市场。<br>Google意识到这小小的掌上机隐含的威胁,然后翻开自己的“收购抽屉”,找到了Android来对抗iPhone。</p><p>很快,Google以免费提供Android操作系统为诱饵,联合灰头土脸的手机生产商们对抗苹果。<br>从此,Android开始腾飞。</p><p><img src="http://images.cnitblog.com/i/413416/201405/131954244067665.png" alt="img"></p><center><strong>移动操作系统份额</strong></center><h2 id="为什么Android会火?"><a href="#为什么Android会火?" class="headerlink" title="为什么Android会火?"></a>为什么Android会火?</h2><p>好的操盘手Google,为了尽快建起防线,对抗苹果,抢占手机市场。为Android量身定做的几个战略方向:</p><ul><li>开放:建立<a href="https://zh.wikipedia.org/wiki/%E9%96%8B%E6%94%BE%E6%89%8B%E6%A9%9F%E8%81%AF%E7%9B%9F" target="_blank" rel="noopener">开放手持设备联盟</a>,联合全世界手机厂商对抗苹果,手机厂商挤不进苹果封闭的系统,也只能搭Android这条船。</li><li>免费:所有人均可以免费获取Android操作系统的授权</li><li>开源:开放源码,可以做OEM深度定制和适配</li><li>廉价:Android主要支持ARM架构的芯片。这一架构以精简节能著称。</li><li>快:Linux、Java<ul><li>在ARM上层,Android使用Linux内核,从而利用Linux丰富的硬件支持,快速适配终端</li><li>在Linux内核之上,Android使用跨平台和被广泛使用的Java来开发应用程序,从而快速开发应用程序</li></ul></li></ul><p>基于以上原因,相比于iPhone长达数年的酝酿,Android不到一年即发布产品!!!<br>但是这种“四处借鉴”的做法也为未来的专利之争埋下祸根。</p><p>对此,本人感受颇深,我从大学毕业后,去了oppo从事Feature Phone的开发,随着iPhone的发布,公司强烈感受到了智能机普及的趋势,其实公司早几年就开始从事智能手机的预研,有试过Windows Mobile,Linux,各种坑。种种原因没办法量产。<br>而安卓的问世,真好比雪中送炭。当时看来,Android无疑是最合适的智能手机系统。我也随大流开始转型学习java和Android系统,从事Android手机系统的研发。</p><p>Android火了,也带动了对Android开发工程师的需求,Android工程师的薪资也水涨船高,由此可见,我们在埋头写代码的同时,也要抽时间了解下发展趋势,要能跟上软件发现潮流。</p><h2 id="免费的怎么赚钱?"><a href="#免费的怎么赚钱?" class="headerlink" title="免费的怎么赚钱?"></a>免费的怎么赚钱?</h2><p>免费的产品、服务就不赚钱?看到这句话,奇虎360看着自己高达100亿美元市值就偷偷地笑了。<br>据外媒报道,谷歌Android操作系统已经创造了310亿美元营收,220亿美元利润,利润率达70%!</p><p>那么问题来了,完全开源免费的安卓系统,到底从哪捞钱的呢?</p><ul><li><p>广告!<br>对于谷歌来说,其搜索、邮件等核心业务虽然并没有直接赚钱,但它们毫无疑问是谷歌广告生态的坚实基础。安卓系统也是如此,它在谷歌移动广告的最佳载体,是谷歌在移动市场不可或缺的一部分。</p></li><li><p>Google Play<br>2015年,GooglePlay的下载量比苹果AppStore高出100%,2014年则是高出60%。也就是说,去年Google Play不仅仅体量更大,增速也要快于App Store。<br>当然,限于安卓应用的质量一般比不上iOS应用,且苹果设备用户更舍得消费,因此App Store的收入比Google Play多75%。</p></li></ul><h2 id="专利战"><a href="#专利战" class="headerlink" title="专利战"></a>专利战</h2><ul><li><p>苹果:<br> Android在移动市场的强势崛起威胁到了苹果的霸主地位。在无法以技术创新拉开距离的前提下,苹果开始动用专利武器,对Android、HTC、三星提起诉讼。</p><p> 然而乔布斯手中的两百多项专利,并不能真正击败Android。通过一些小的改动,比如将横向滑动的解锁改为不定向的滑动,Android就可以避开专利陷阱。而三星甚至因为苹果的诉讼,提高了在美国市场的知名度。</p><p> PS:专利大战后,一种特殊人才火了,那就是即懂Android又懂专利的工程师。</p><p> 然而,Google自己也没有预期到Android的成功,暗自后悔最初太保守。三星在Android阵营中的一家独大也让Google心生警惕。Google花大价钱收购了摩托罗拉,打造自己的硬件生产线,更获得了摩托罗拉的大量专利,用来对抗专利战。</p></li><li><p>Oracle:<br> 从Sun手中买过Java后,Oracle还没有从Java中获得太大的利益。而Oracle手中的Java,也发展缓慢。然而这并不妨碍Oracle对Android的觊觎。<br> Oracle对Google提起诉讼,索赔93亿美金,相对于此,Oracle收购Sun的56亿美元,显得便宜得多。</p><p> 其诉讼理由是“Google对Java API的改动,破坏了Java平台的完整性”。听起来有些空洞,却支撑起百亿美元的专利案。</p><p> Android为开发基于Java语言的App应用提供的API接口分为两部分,一部分是代码库的 API 接口,另一部分是 Google 开发的可以让该代码库工作的实现代码。Java 的开发者 Oracle 自己提供了两种实现代码库的方式,一种是自有版权的 JDK 版本,另一种是开源的 OpenJDK 版本。OpenJDK 之前就在 Android 的某些方面得到应用,现在将投入更多精力到 OpenJDK。</p></li></ul><h2 id="历史版本"><a href="#历史版本" class="headerlink" title="历史版本"></a>历史版本</h2><p><img src="http://images.cnitblog.com/i/413416/201405/132143561562639.png" alt=""></p><ul><li><p>2008年9月23日 Android 1.0(Astro)<br> 主要特性:</p><pre><code>Android Market各种App:相机、浏览器、Email、联系人、地图、多媒体播放器等支持Wifi和蓝牙等等等</code></pre></li><li><p>2009年4月17日 Android 1.5(Cupcake)<br> 主要特性:</p><pre><code>播放视频浏览器支持WebKet支持手机旋转应用程序UI大幅改进等等等</code></pre></li><li><p>2009年9月15日 Android 1.6(Donut)<br> 主要特性:</p><pre><code>手势支持支持CDMA网络支持更多屏幕分辨率等等等</code></pre></li><li><p>2009年10月26日 Android 2.0/2.1(Eclair)<br> 主要特性:</p><pre><code>改良UI优化硬件速度全新的APP更新支持动态桌面设计等等</code></pre></li><li><p>2010年5月20日 Android 2.2(Froyo)<br> 主要特性:</p><pre><code>支持内存卡加快软件即时编译的速度WIFI热点及USB分析器速度和性能优化等等</code></pre></li><li><p>2010年12月7日 Android 2.3(Gingerbread)<br> 主要特性:</p><pre><code>系统级粘贴复制重新设计的多点触摸屏幕键盘支持NFC、陀螺仪、气压计改善电池耗电量,增加续航时间下载和屏幕截图等功能等等</code></pre></li><li><p>2011年2月2日 Android 3.0(Honeycomb)<br> 主要特性:</p><pre><code>仅供平板电脑使用3D加速处理UI改进等等</code></pre></li><li><p>2011年5月11日 Android 3.1(Honeycomb)</p></li><li><p>2011年7月13日 Android 3.2(Honeycomb)</p></li><li><p>2011年10月19日 Android 4.0(Ice Cream Sandwich)<br> 主要特性:</p><pre><code>统一了手机和平板电脑使用的系统,应用会自动根据设备选择最佳显示方式提升硬件的性能以及系统的优化,提升系统流畅度支持在系统中使用虚拟按键,该功能可以取代物理按键更好的语音集成,实时录音,文本听写等语音功能脸部识别进行锁屏,可以通过脸部识别进行锁屏增加支持硬件加速的功能等等</code></pre></li><li><p>2012年6月28日 Android 4.1(Jelly Bean)<br> 主要特性:</p><pre><code>修复Android 4.0中的Bug“黄油”性能(Project Butter)通知中心显示更多消息等等</code></pre></li><li><p>2012年10月30日 Android 4.2(Jelly Bean)<br> 主要特性:</p><pre><code>手势输入键盘改进锁屏:支持Widget,可于屏幕锁定界面直接打开相机功能。可直接进行操作的状态通知列功能连点三次可放大整个显示页及两指旋转和缩放增加为盲人用户设计的语音输出及手势模式导航功能内置时钟新增世界时钟,秒表和定时器Google Now新增以Gmail登录信息作为数据源Google Now新增航班追踪功能、酒店、餐厅预订,与音乐和电影推荐功能。Gmail邮件可缩放显示等等</code></pre></li><li><p>2013年7月25日 Android 4.3(Jelly Bean)<br> 主要特性:</p><pre><code>支持多用户登录,支持一台终端设备上有多个登录帐号。“蓝牙低功耗”功能,开启蓝牙后,耗电量相比之前大幅降低。支持更多缓冲器对象新版OpenGL ES 3.0着色语言,支持32 位整数和浮点数据类型以及操作。增加多个纹理的支持,包括浮点纹理、深度纹理、顶点纹理等等。多重渲染目标,让GPU一次性渲染多个纹理。多重采样抗锯齿,让3D物体的边缘不出现毛刺,可提升图像效果。使用统一的纹理压缩格式ETC增加TRIM指令,使得内置存储(Internal Storage)不会越用越慢。新增App Opt功能(默认隐藏),允许用户强行解除已安装应用的特定权限。等等</code></pre></li><li><p>2013年11月1日 Android 4.4(KitKat)<br> 主要特性:</p><pre><code>支持语音打开Google Now (在主画面说出“OK Google”)在阅读电子书、玩游戏、看电影时支持全屏模式(Immersive Mode)优化存储器使用,在多任务处理时有更佳工作的表现。新的电话通信功能旧有的SMS应用程序集成至新版本的Hangouts应用程序Emoji Keyboard 集成至Google本地的键盘支持Google Cloud Print服务,让用户可以利用户中或办公室中连接至Cloud Print的打印机,印出文件。支持第三方Office应用程序直接打开及存储用户在Google Drive内的文件,实时同步更新文件。支持低电耗音乐播放全新的原生计步器全新的NFC付费集成全新的非Java虚拟机运行环境ART(Android Runtime)支持Message Access Profile(MAP)支持Chromecast及新的Chrome功能支持隐闭字幕等等</code></pre></li><li><p>2014年10月16日 Android 5.0(Lollipop)<br> 主要特性:</p><pre><code>采用全新Material Design界面支持64位处理器全面由Dalvik转用ART(Android Runtime)编译,性能可提升四倍改良的通知界面及新增优先模式预载省电及充电预测功能新增自动内容加密功能新增多人设备分享功能,可在其他设备登录自己账号,并获取用户的联系人、日历等Google云数据强化网络及传输连接性,包括Wi-Fi、蓝牙及NFC强化多媒体功能,例如支持RAW格式拍摄强化“OK Google”功能改善Android TV的支持提供低视力的设置,以协助色弱人士改善Google Now功能等等</code></pre></li><li><p>2015年5月28日 Android M(Marshmallow)<br> 主要特性:</p><pre><code>应用权限管理SD卡可能和内置存储“合并”Android Pay原生指纹识别认证自动应用数据备份App Links(尽量减少诸如“你想要使用什么来打开这个?”的提醒)打盹和应用待机功能多窗口(隐藏技能,未来不确定)主题支持(隐藏技能,未来不确定)等等</code></pre></li><li><p>??? Android N(Eclair)<br> 主要特性:</p><pre><code>分屏多任务全新下拉快捷开关页通知消息快捷回复通知消息归拢夜间模式流量保护模式全新设置样式改进的Doze休眠机制系统级电话黑名单功能菜单键快速应用切换等等</code></pre></li></ul><p>Google的安卓系统开发团队是一个世界级的团队,内部采用敏捷开发流程,每个版本发布都有越来越完善的功能和体验、软硬整合的能力越来越强、服务越来越全面。<br>安卓也顺势成为智能手机第一平台,把iOS拉下马。</p><h2 id="关于抄袭"><a href="#关于抄袭" class="headerlink" title="关于抄袭"></a>关于抄袭</h2><p>在安卓和iOS粉丝之间,“抄袭”是一个永恒的话题。</p><p>我们归纳如下:</p><p>1、触控和外观设计:安卓抄袭iOS</p><p>安卓最初并不是一个为触屏设计的操作系统,其原型机是类似黑莓的全键盘机型。</p><p><img src="http://images.cnitblog.com/i/413416/201405/132216415315772.jpg" alt=""><br><img src="http://img1.mydrivers.com/img/20160623/a259c377-8e88-42e6-b9ec-2fe1eba0b256.jpg" alt=""></p><p>但是,当iPhone横空出世后,Android似乎一下子就懵了。开始奋起直追的“Copy”。<br>事实上,世界上绝大多数手机公司都开始抄袭。</p><p>外观:<br><img src="/2016/07/12/android-story/sanxing.jpg" alt="img"><br>UI:<br><img src="/2016/07/12/android-story/sanxing_ui.jpg" alt="img"><br>甚至数据线:<br><img src="/2016/07/12/android-story/sanxing_dataline.jpg" alt="img"></p><p>2、扁平化UI:是抄袭还是大势所趋?</p><p>其实在移动操作系统这一块,先使用扁平化设计的是微软的Windows Phone。</p><p>iOS使用了毛玻璃堆叠层级,而安卓的Material Design大量使用了阴影造就剪纸效果,WP则是使用了类似杂志的图文混排设计UI。</p><p><img src="http://img1.mydrivers.com/img/20160623/d0963020-db46-4c4c-944c-79547ff4696c.png" alt="img"></p><p>3、卡片设计:大家都抄WebOS?</p><p><img src="http://img1.mydrivers.com/img/20160623/c79875bc-0f1f-46bf-85aa-e41b3574a030.jpg" alt="img"></p><p>遗憾的是由于生态系统等种种原因,WebOS并没有流行起来。但是这并不意味着WebOS的优雅设计就此消失在人海——Google挖角了WebOS的设计师,安卓4.0的Holo界面,就是此种背景下的产物了。</p><p>4、通知中心:到底谁先抄?</p><p>这个设计在这三个系统中,最早的确先出现于安卓。很快,iOS上也出现了类似的设计,安卓粉丝们纷纷指责称苹果抄袭了安卓的想法。</p><p><img src="http://img1.mydrivers.com/img/20160623/d07d24d2-5b4f-4054-8e6f-90995e202b58.jpg" alt="img"></p><p>其实这个设计在WebOS中出现得更早;而在通知栏下拉呼出通知中心的设计,iOS某个越狱插件也已经实现过。</p><p>5、分屏多任务:齐齐抄袭Win?</p><p><img src="http://img1.mydrivers.com/img/20160623/4187d618-8313-4cd7-b1ba-5d8e2f087cc0.jpg" alt="img"></p><p>类似的设计最早可以追溯到Win7,微软在Win7中引入AeroPeek。这个设计可以让用户只需要简单把窗口拖拽到屏幕边缘,就很方便地左右并排两个窗口。</p><p>6、语音助手、指纹、健康中心、支付等功能:iOS引领潮流</p><p><img src="http://img1.mydrivers.com/img/20160623/b03cbde9-6e9c-47fc-8748-5820c4db01fc.jpg" alt="img"></p><p>苹果iOS4中先推出了智能语音助手Siri,安卓很快就在安卓4.1中用Google Now跟上步伐;苹果先在iOS7中先加入了指纹识别,而安卓则在安卓5.1中跟进。此外,还有健康中心、移动支付等功能,都是iOS率先推向市场。</p><p>乔布斯:“好的艺术家拷贝,伟大的艺术家剽窃”<br>在移动互联网的大环境下,如何将生态整合到设备中,让自家的服务全方面包围用户的生活,是IT企业们的共同愿景。在此种思路下,加上触屏设备硬件上又没有大突破,移动操作系统越做越相似,也是在情理之中。</p><h2 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h2><p><img src="/2016/07/12/android-story/android-framework.png" alt="img"></p><center><strong>Android系统架构图</strong></center><p>我们从底层 <strong>内核层</strong> 开始。<br>Android基于Linux2.6内核,其优势是“站在巨人的肩膀上”,其核心系统服务如安全性、内存管理、进程管理、网路协议以及驱动模型都依赖于Linux内核。且异常稳定可靠。</p><p>往上看,接下来是 <strong>系统运行库层</strong>,分为系统库和Android运行时环境。</p><ul><li>系统库:提供了对应用程序框架的支持,用C++开发,俗称Native层。<br> 比如SurfaceManager负责管理显示,2D、3D的绘图进行显示合成。</li><li>Android运行时环境:<br> Android应用程序时采用Java语言编写,程序在Android运行时中执行,其运行时分为核心库和Dalvik虚拟机两部分。<ul><li>核心库:<br>提供了Java语言API中的大多数功能,同时也包含了Android的一些核心API,如android.os、android.net、android.media等等。</li><li>Dalvik虚拟机:负责执行App代码:<br>1、每个Android应用程序都有一个专有的进程,并且不是多个程序运行在一个虚拟机中,而是每个Android程序都有一个Dalivik虚拟机的实例,并在该实例中执行。<br>2、Dalvik虚拟机是一种基于寄存器的Java虚拟机,而不是传统的基于栈的虚拟机,并进行了内存资源使用的优化以及支持多个虚拟机的特点。<br>3、Android程序在虚拟机中执行的并非编译后的字节码,而是通过转换工具dx将Java字节码转成dex格式的中间码。</li></ul></li></ul><p>继续往上: <strong>Framework层</strong><br>应用程序框架层是我们从事Android开发的基础,很多核心应用程序也是通过这一层来实现其核心功能的,该层简化了组件的重用,开发人员可以直接使用其提供的组件来进行快速的应用程序开发,也可以通过继承而实现个性化的拓展。</p><pre><code>- Activity Manager(活动管理器):管理各个应用程序生命周期以及通常的导航回退功能- Window Manager(窗口管理器):管理所有的窗口程序</code></pre><p>最后是 <strong>应用程序层</strong><br>Android平台不仅仅是操作系统,也包含了许多应用程序,诸如SMS短信客户端程序、电话拨号程序、图片浏览器、Web浏览器等应用程序。<br>这些应用程序都是用Java语言编写的,并且这些应用程序都是可以被开发人员开发的其他应用程序所替换,这点不同于其他手机操作系统固化在系统内部的系统软件,更加灵活和个性化。</p><p>本人在OPPO工作的几年中,主要负责Framework层的工作,后来入职腾讯后,负责App开发。<br>由于兴趣使然,从底层到最上层都有参与研发:最开始基于HAL编写内核层收音机的驱动,然后写收音机的Native服务和Framework服务,最后写收音机的App。整套打通后,基本能把Android系统架构大致了解清楚。</p><p>引用一个一般大家对整个Android系统开发的理解:<br><img src="/2016/07/12/android-story/hanbao.png" alt="img"><br>Linux系统内核层对应汉堡最底层面包<br>Native层对应中间的鸡腿肉<br>Framework层对应汉堡顶层面包<br>而App只是汉堡上的星星点点的芝麻</p><p>对我而言,如果一定要赞同这种类比的话,我觉得最香的其实是芝麻。<br>我其实不认同这种类比,我更赞同下图:<br><img src="/2016/07/12/android-story/dashu.png" alt="img"><br>内核层是我们的根<br>Native层对应大树的主干<br>Framework层对应大树的枝干<br>而App,则是绿叶,是最有生机的部分</p><p>对于应用开发,一般做底层的都瞧不起做上层的,觉得上层基于自己做的基础上再做开发,没有技术含量。<br>其实对我而言,我的工作经历告诉我,每个层次其实是分工不同、侧重点不同,涉及到的技术面不一样而已。<br>做应用的,更在意解耦、可扩展性、在开发过程中,设计模式,架构也必不可少,<br>做底层的,更在意数据结构、运行效率、在意算法,<br>当然这不是绝对,但是每个方向都有自己的侧重点,都可以做得有技术含量。<br>我想说的是,在这里想告诉各位开发者,没必要厚此薄彼或者自惭形秽。</p><h2 id="技术现状"><a href="#技术现状" class="headerlink" title="技术现状"></a>技术现状</h2><p>Android经过近8年的发展,系统越来越成熟,各种技术方案也越来越完善,开源框架井喷。<br>仔细想了下,真是浩瀚博大,我只能进行简单的归纳总结,其实每一个小点都可以展开讲。以后有事件了,可以挑一下来细讲。</p><p>我从如下几个方向介绍下安卓技术现状:</p><p>1、开发环境:</p><ul><li>打包:安卓App的打包,最开始流行用Ant,现在已经被Gradle取代。快速打多渠道包。</li><li>混淆:混淆能提高App被反编译的门槛,提高安全性,也能减小App包大小。</li><li>IDE:Eclipse已经被Android Studio取代。</li><li>模拟器:虽然Android SDK自带模拟器性能有所提升,但是还是没有Genymotion好用。</li><li>自动构建:Jenkins省时省心的完成应用的自动构建和发布。</li></ul><p>2、 开发:</p><ul><li>各种View类开源框架:。。。数不尽的库,看不完的各种框架</li><li>系统支持:<br> 为了提供更多好用的功能,而不依赖Android版本,Google官方提供了Support Library,用来向下兼容版本。应用集成后,就能使用这些功能,而不用考虑Android系统版本。<pre><code>包括:工具类:Multidex系统App组件:Fragment、NotificationCompat、ActionBarActivityUI类:Fragment、Viewpager、CardView、RecycleView、GridLayout、主题&&设计类:Holo、Material Design</code></pre></li><li>网络:各种网络框架层用来提供更好的网络服务和封装<pre><code>HttpClient、HttpUrlConnection、OKHttp、HttpRequest、android-async-http、Volley等</code></pre></li><li>图片:解决图片管理,图片下载,图片内存管理、图片处理等各种服务<pre><code>UIL、Picasso、ImageLoader、Glice、以及新宠Fresco</code></pre></li><li>解耦:EventBus、Otto</li><li>降低代码量&&依赖注入:Dagger2、ButterKnife</li><li>数据库:OrmLite、GreenDao</li><li>java支持库:<a href="http://code.google.com/p/guava-libraries" target="_blank" rel="noopener">Guava</a>:基于java1.6的类库集合的扩展项目</li></ul><p>3、 调试和测试:<br> 调试:stetho<br> 内存泄露检查工具:Leakcanary<br> 测试框架:Robotium、uiautomator、Espresso</p><p>4、 语言和模式:</p><p>语言:</p><ul><li><p>Kotlin: 与Java相比,Kotlin的语法更简洁、更具表达性,而且提供了更多的特性。号称Android领域的Swift<br> <img src="/2016/07/12/android-story/converted-code.png" alt=""></p></li><li><p>Sky: 使用Web开发语言来做移动平台的开发,让App更流畅</p></li><li><p>Swift? </p></li></ul><p>模式:</p><ul><li><p>MVP:Model-View-Presenter。View和Model不发现联系,通过Presenter传递。<br><img src="http://image.beekka.com/blog/2015/bg2015020109.png" alt=""></p></li><li><p>MVVM:Model-View-ViewModel。基于数据绑定,View的变动,自动反映在 ViewModel。<br><img src="http://image.beekka.com/blog/2015/bg2015020110.png" alt=""></p></li><li><p>ReactiveX:响应式编程。基于事件流和观察者模式,面向数据流和变化传播的编程范式。可以写出很优美、逻辑清晰的代码,从此告别并发和Callback Hell</p><p> 举例有这样一个需求:界面上有一个自定义的视图 imageCollectorView ,它的作用是显示多张图片,并能使用 addImage(Bitmap) 方法来任意增加显示的图片。现在需要程序将一个给出的目录数组 File[] folders 中每个目录下的 png 图片都加载出来并显示在 imageCollectorView 中。需要注意的是,由于读取图片的这一过程较为耗时,需要放在后台执行,而图片的显示则必须在 UI 线程执行。</p><p> before:</p> <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Thread() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.run();</span><br><span class="line"> <span class="keyword">for</span> (File folder : folders) {</span><br><span class="line"> File[] files = folder.listFiles();</span><br><span class="line"> <span class="keyword">for</span> (File file : files) {</span><br><span class="line"> <span class="keyword">if</span> (file.getName().endsWith(<span class="string">".png"</span>)) {</span><br><span class="line"> <span class="keyword">final</span> Bitmap bitmap = getBitmapFromFile(file);</span><br><span class="line"> getActivity().runOnUiThread(<span class="keyword">new</span> Runnable() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> imageCollectorView.addImage(bitmap);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}.start();</span><br></pre></td></tr></table></figure><p> after:</p> <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Observable.from(folders)</span><br><span class="line"> .flatMap((Func1) (folder) -> { Observable.from(file.listFiles()) })</span><br><span class="line"> .filter((Func1) (file) -> { file.getName().endsWith(<span class="string">".png"</span>) })</span><br><span class="line"> .map((Func1) (file) -> { getBitmapFromFile(file) })</span><br><span class="line"> .subscribeOn(Schedulers.io())</span><br><span class="line"> .observeOn(AndroidSchedulers.mainThread())</span><br><span class="line"> .subscribe((Action1) (bitmap) -> { imageCollectorView.addImage(bitmap) });</span><br></pre></td></tr></table></figure></li><li><p>AOP:面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。特别适用于日志和上报,监控等模块。</p></li><li><p>ReactNative:跨IOS和Android平台,结合了Web应用和Native应用的优势,可以使用JavaScript来开发iOS和Android原生应用。在JavaScript中用React抽象操作系统原生的UI组件,代替 DOM 元素来渲染等。</p></li><li><p>插件化:动态发布某个功能或者解决线上版本crash等问题</p></li></ul><p>5、 设计:<br><a href="https://material.google.com/" target="_blank" rel="noopener">Material Design</a>: 跨平台体验的一套设计语言。由于规范严格细致,保证它在各个平台使用体验高度一致。开发工程师只要遵循规范,自己做出来的UI就很美。<br> <img src="http://image.uisdc.com/wp-content/uploads/2014/12/a-2.png" alt=""></p><p>6、 各种快速集成的公共解决方案:云存储、图片存储和处理服务、统计服务、Crash上报服务等</p><p>安卓开发越来越繁荣,也越来越容易。</p><h2 id="趋势"><a href="#趋势" class="headerlink" title="趋势"></a>趋势</h2><ul><li><p>更智能:<br> Awareness API:根据用户设备环境使用作出更加智能化的反馈,让设备比用户更了解自己。<br> 比如:用户进行户外健身,驾车长途行驶和专心工作等情境下为其推荐不同类型的音乐。<br> <img src="/2016/07/12/android-story/awareness.jpg" alt=""></p></li><li><p>更多领域:<br> 物联网:Android Home<br> <img src="http://img2.cache.netease.com/tech/2013/6/3/20130603041829110fc.jpg" alt=""><br> 智能家居:Android Wear<br> <img src="http://img2.imgtn.bdimg.com/it/u=3961033792,439519670&fm=21&gp=0.jpg" alt=""><br> 电视:Android TV<br> <img src="http://img00.hc360.com/home-a/201501/201501071133023174.jpg" alt=""><br> 汽车:Android Auto<br> <img src="http://i3.sinaimg.cn/qc/2014/0714/U5336P33DT20140714155126.jpg" alt=""><br> 非Google:<br> Fire OS:Kindle电子书操作系统<br> <img src="http://upload.news.cecb2b.com/2014/0224/1393233308195.jpg" alt=""><br> Remix OS: 基于x86的PC操作系统<br> <img src="http://static.oschina.net/uploads/img/201601/13073853_W2eA.png" alt=""></p></li></ul><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://tech.sina.com.cn/t/2011-06-11/04185636037.shtml" target="_blank" rel="noopener">http://tech.sina.com.cn/t/2011-06-11/04185636037.shtml</a><br><a href="http://www.cnblogs.com/vamei/p/3726620.html" target="_blank" rel="noopener">http://www.cnblogs.com/vamei/p/3726620.html</a><br><a href="http://news.mydrivers.com/1/488/488214.htm" target="_blank" rel="noopener">http://news.mydrivers.com/1/488/488214.htm</a><br><a href="http://baike.baidu.com/link?url=zFVxfPvBmiDBiA33REdgpd0utwmnLpnBR2AzppwUNSeLYiYt-FtfzpS742nNycGiA04nt1hrXEbyY8vFdxFTBq" target="_blank" rel="noopener">http://baike.baidu.com/link?url=zFVxfPvBmiDBiA33REdgpd0utwmnLpnBR2AzppwUNSeLYiYt-FtfzpS742nNycGiA04nt1hrXEbyY8vFdxFTBq</a></p>]]></content>
<summary type="html">
<p>懒癌发作好久没更新了,最近得空想放个大招,写写自己的老本行,天马行空的介绍下安卓的发展历程和历史。</p>
<p>总结下,我想讲如下几个方面:</p>
<ul>
<li>Android之父</li>
<li>Google为什么收购Android</li>
<li>发展历程</li>
<li>Android为什么会火</li>
<li>免费的怎么赚钱</li>
<li>专利战</li>
<li>历史版本</li>
<li>关于抄袭</li>
<li>架构</li>
<li>技术发展现状</li>
<li>趋势</li>
</ul>
<p>好像一下写太多,有些题目又太大了。–!</p>
</summary>
<category term="技术" scheme="http://lightom.cc/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Android" scheme="http://lightom.cc/tags/Android/"/>
<category term="简史" scheme="http://lightom.cc/tags/%E7%AE%80%E5%8F%B2/"/>
</entry>
<entry>
<title>从娃娃机说起</title>
<link href="http://lightom.cc/2016/05/03/about-gamble/"/>
<id>http://lightom.cc/2016/05/03/about-gamble/</id>
<published>2016-05-03T07:37:35.000Z</published>
<updated>2016-05-03T07:43:40.000Z</updated>
<content type="html"><![CDATA[<p>每次路过抓娃娃机,都会被里面的好东西吸引,不少妹子更是对娃娃没有抵抗力,用充满期待的大眼睛看着旁边的GG,GG们一看,一块钱一次,开心的笑了,看我的抓娃娃神功。<br><a id="more"></a><br>接下来这一幕是不是特别熟悉<br><img src="/2016/05/03/about-gamble/zhuawawa1.gif" alt=""></p><p>然后我们深陷其中无法自拔,疯狂找寻攻略和技巧,下定决心苦练技术<br><img src="/2016/05/03/about-gamble/zhuawawa3.png" alt=""><br><img src="/2016/05/03/about-gamble/zhuawawa4.png" alt=""></p><p>力求达到如下境界,并抱得美人归:<br><img src="/2016/05/03/about-gamble/zhuawawa2.jpg" alt=""></p><p>那么问题来了。<br>对这种满大街都有的娃娃机,我的看法是,它首先是商家花钱购买的机器,唯一的目的是为了赚钱。<br>如果真的可以通过某种技巧来抓娃娃,一抓一个准,哪里还会有商家会花钱来承受这样的风险呢?</p><p>为了验证我的想法,我特地从网上找了一份自动贩卖娃娃机调整说明书<br><img src="/2016/05/03/about-gamble/zhuawawashuoming.png" alt=""></p><p>里面详细说明了对娃娃机游戏功能的调整模式<br><img src="/2016/05/03/about-gamble/zhuawawashuoming2.jpg" alt=""></p><p>这下大家都明白了吧?你是否能抓到娃娃的概率,完全是由商家控制的。你只是一个触发抓娃娃行为的发起者和投币人。而且我可以向你保证,你抓到娃娃的平均成本一定高于娃娃的成本。</p><p>有一位前辈对抓娃娃机的点评真是一针见血:<br><img src="/2016/05/03/about-gamble/zhuawawa5.jpg" alt=""></p><p>如果带着“天下熙熙,皆为利来;天下攘攘,皆为利往”的看法去看世界,你会发现很多这样的例子,特别是游戏厅,比如一直流行的水果机、最近比较火的捕鱼游戏等等。</p><p>我读小学的时候长期泡游戏厅,有一段时间着迷着水果机,当时1块钱买4个游戏币,水果机的中奖率从5到100,也就是说,只要中了,最少都可以一个游戏币变5个游戏币,有一段时间我站在水果机旁边背诵着中奖的结果,试图找出中奖规律。然后梦想着以后打游戏机不花钱并为自己的这个目标而激动不已。<br>现在想起来,其实游戏厅老板每隔2个小时,拿着钥匙打开水果机,拿走大量“收获”的游戏币的时候,我就应该知道这是一个必输局。</p><p>不知道为什么会有这么多人看不开,败光了自己的财产,最后却觉得只是运气不好。<br>我想,可能是心里的一个贪念,妄想不劳而获。<br>而很多骗子就是利用了这一点,一般套路都是给你一个以小博大,用小钱赚大钱的机会,机会“看起来”越大就越受欢迎。<br>类似的例子还可以引申到很多地方,比如赌博,六合彩等等。</p><p>所以以后遇到类似的东西,不妨从这个角度来看问题。自己不贪,就不容易受骗。</p><p>ps: 文章的排版挺不好看的,我想我可能需要学习一下markdown的格式。</p>]]></content>
<summary type="html">
<p>每次路过抓娃娃机,都会被里面的好东西吸引,不少妹子更是对娃娃没有抵抗力,用充满期待的大眼睛看着旁边的GG,GG们一看,一块钱一次,开心的笑了,看我的抓娃娃神功。<br></p>
</summary>
<category term="生活" scheme="http://lightom.cc/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="娃娃机" scheme="http://lightom.cc/tags/%E5%A8%83%E5%A8%83%E6%9C%BA/"/>
</entry>
<entry>
<title>step by step创建专属博客</title>
<link href="http://lightom.cc/2016/04/28/step-by-step-to-make-bolg-1/"/>
<id>http://lightom.cc/2016/04/28/step-by-step-to-make-bolg-1/</id>
<published>2016-04-28T03:47:51.000Z</published>
<updated>2017-06-30T09:33:47.000Z</updated>
<content type="html"><![CDATA[<h2 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h2><p>花1分钟想想我们的目标:博客,它有自己独立的域名,有一个能存放我们的博客html文件的地方,然后我们也需要一套比较快速且高效的博客框架来迅速搭建我们的博客,让我们能很方便的排版布局,发布内容,定义样式甚至是切换主题。</p><p>基于以上需求,业界已经有非常成熟的解决方案了:Hexo+Github Pages</p><p>接下来,跟着tom一起,step by step无门槛的完成搭建博客之旅吧。<br><a id="more"></a></p><h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><ol><li>用Hexo搭建本地博客</li><li>把本地博客部署到github</li><li>购买域名,把域名绑定到github</li><li>自定义Hexo主题和排版布局</li><li>发表文章</li><li>洗洗睡觉</li></ol><h2 id="Step-1-用Hexo搭建本地博客"><a href="#Step-1-用Hexo搭建本地博客" class="headerlink" title="Step 1 用Hexo搭建本地博客"></a>Step 1 用Hexo搭建本地博客</h2><p>我们的第一步是在电脑上搭建一个本地的博客,并通过浏览器预览。</p><p>完成这个工作,全靠<a href="https://hexo.io/zh-cn/" target="_blank" rel="noopener">Hexo</a>这个快速、简洁且高效的博客框架。</p><p>Hexo基于nodejs,所以要确保自己已经安装了<a href="http://nodejs.cn/" target="_blank" rel="noopener">node</a></p><p>通过以下命令行安装Hexo<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ npm install hexo-cli -g #安装hexo</span><br><span class="line">$ hexo init blog #创建blog文件夹,并初始化</span><br><span class="line">$ cd blog</span><br><span class="line">$ npm install #安装相关依赖库</span><br><span class="line">$ hexo server #启动本地服务器,这样我们就能在本地通过浏览器访问博客了</span><br></pre></td></tr></table></figure></p><p>用浏览器打开<a href="http://0.0.0.0:4000/" target="_blank" rel="noopener">http://0.0.0.0:4000/</a>即可看到我们搭建起来的博客,五脏六腑一应俱全。</p><h2 id="Step-2-把本地博客部署到github"><a href="#Step-2-把本地博客部署到github" class="headerlink" title="Step 2 把本地博客部署到github"></a>Step 2 把本地博客部署到github</h2><p>到此,我们只能在本地浏览我们的博客,我们需要把我们的博客搬到互联网上,让其他人看到它。放到哪里好呢?我们选择了Github Pages。它本用于介绍托管在github的项目,提供静态站点托管服务。</p><h4 id="Why-Github-Pages"><a href="#Why-Github-Pages" class="headerlink" title="Why Github Pages"></a>Why Github Pages</h4><p>这里我引用前人的描述:</p><ol><li>github pages有300M免费空间,资料自己管理,保存可靠;</li><li>学着用 github,享受 github 的便利,上面有很多大牛,眼界会开阔很多;</li><li>顺便看看 github 工作原理,最好的团队协作流程;</li><li>github 是趋势;</li><li>你不觉得一个文科生用 github 很 geek 吗?瞬间跻身技术界;</li><li>就算 github 被墙了,还可以搬到国内的 gitcafe 中去。</li></ol><p>而我比较看重的是:免费、简单方便。</p><p>我们首先注册一个<a href="https://github.com/" target="_blank" rel="noopener">github</a>账号,并<a href="https://pages.github.com/" target="_blank" rel="noopener">创建github pages的仓库</a>。</p><p>创建成功后,通过域名<a href="http://username.github.io,就可以访问我们的github" target="_blank" rel="noopener">http://username.github.io,就可以访问我们的github</a> pages。接下来我们的工作就很简单了:把博客的html等文件传到仓库</p><p>一个想当然的办法是直接生成博客系统,把public里面的文件通过git命令上传上去。<br>但是做为一个懒惰的,有追求的程序员,这明显是不标准的做法,Hexo必须得有一键上传的功能。</p><p>我们查阅Hexo的<a href="https://hexo.io/zh-cn/docs/commands.html" target="_blank" rel="noopener">api</a>,果然有。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy #部署网站</span><br></pre></td></tr></table></figure><p>但是在运行这个命令之前,我们需要做一些设置:ssh、hexo config<br>ssh的目的是通过github的验证,毕竟不是所有人都能传文件到我们的github仓库<br>hexo config的目的是告诉hexo把博客文件传到我们正确的仓库地址。</p><ul><li>配置github ssh看<a href="http://blog.csdn.net/binyao02123202/article/details/20130891" target="_blank" rel="noopener">这里</a></li><li>配置hexo config:<ul><li>打开你所在博客系统的文件夹,打开根目录下的_config.yml</li><li>找关键字deploy</li><li>配置相关信息<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">deploy:</span><br><span class="line"> type: git</span><br><span class="line"> repository: git@github.com:username/username.github.io.git</span><br><span class="line"> branch: master</span><br></pre></td></tr></table></figure></li></ul></li></ul><p>搞完之后,一键部署博客到github<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy #部署网站</span><br></pre></td></tr></table></figure></p><p>此时的你,打开浏览器,输入<a href="http://username.github.io就能看到自己的博客。" target="_blank" rel="noopener">http://username.github.io就能看到自己的博客。</a></p><h2 id="Step-3-购买域名,把域名绑定到github"><a href="#Step-3-购买域名,把域名绑定到github" class="headerlink" title="Step 3 购买域名,把域名绑定到github"></a>Step 3 购买域名,把域名绑定到github</h2><p>现在我们的博客地址其实是github的一个二级域名,通过顶级域名访问博客是一个逼格更高的体验。<br>所以我购买一个域名,并把域名和我们的github pages绑定。访问任何一个域名都会打开我们的博客。</p><p>so,让我们买买买<br>买域名有人推荐<a href="https://wanwang.aliyun.com/" target="_blank" rel="noopener">万网</a>,有人只推荐<a href="https://sg.godaddy.com/zh/" target="_blank" rel="noopener">godaddy</a>, 我最后选择了万网,万网的购买体验更好,如果你想要的域名没有了,它会跟你推荐其他后缀或者相近的域名。我当时选的时候com的已经木有了,最后选了cc这个后缀的域名:),支付宝支付,3年54块钱,不贵。<br><img src="/2016/04/28/step-by-step-to-make-bolg-1/maiyuming.png" alt="logo"></p><p>域名有了,接下来就是绑定域名咯。通过配置DNS即可。</p><ol><li>添加CNAME文件<br>在仓库根目录下添加一个CNAM文件,没有后缀名,里面内容为你的域名(如:lightom.cc),不需要添加http/www等前缀。</li><li>添加 DNS Service记录<br>去<a href="https://www.dnspod.cn/" target="_blank" rel="noopener">DNSPod</a>注册个账号,添加域名,设置两个A记录。分别是@和www,ip地址填上个步骤获取的IP地址。</li><li>设置域名的DNS<br>在相应域名的Custom DNS里,设置DNS service,添加两条记录f1g1ns1.dnspod.net和f1g1ns2.dnspod.net</li><li>漫长的等待<br>要全球解析生效,得等上一会了,也可以先ping一下自己的设置对不对。</li></ol><p>此时通过我们自己购买的域名就能够访问我们自己的博客了。是不是有点小成?</p><h2 id="Step-4-自定义Hexo主题和排版布局"><a href="#Step-4-自定义Hexo主题和排版布局" class="headerlink" title="Step 4 自定义Hexo主题和排版布局"></a>Step 4 自定义Hexo主题和排版布局</h2><p>接下来就是专心打理博客的时间,我们会对当前博客的主题和排版布局挑三拣四,评头论足,寻找一个高大上、简约不简单的框架。<br>有牛人利用爬虫系统抓取,统计出最受欢迎的Hexo主题是<a href="http://theme-next.iissnan.com/" target="_blank" rel="noopener">nexT</a></p><p>所以我们直接拿来用</p><p>1.下载<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ cd your-hexo-site</span><br><span class="line">$ git clone https://github.com/iissnan/hexo-theme-next themes/next</span><br></pre></td></tr></table></figure></p><p>2.修改_config.yml文件<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Extensions</span><br><span class="line">## Plugins: http://hexo.io/plugins/</span><br><span class="line">## Themes: http://hexo.io/themes/</span><br><span class="line">theme: next</span><br></pre></td></tr></table></figure></p><p>再次刷新后就能看到新的主题了。</p><p>我们需要花一些时间<a href="http://theme-next.iissnan.com/getting-started.html" target="_blank" rel="noopener">配置主题</a>,包括语言、菜单、侧栏、头像等。<br>还可以增加第三方服务,比如评论、统计等等。</p><p>配置主题的过程中会遇到一些配置问题,可以看<a href="https://github.com/iissnan/hexo-theme-next/wiki" target="_blank" rel="noopener">这里</a>。</p><h2 id="Step-5-发表文章"><a href="#Step-5-发表文章" class="headerlink" title="Step 5 发表文章"></a>Step 5 发表文章</h2><p>现在美美的博客框架已经准备就绪,只差东风(文章)了。</p><p>发布文章:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new [layout] <title> #发表文章</span><br></pre></td></tr></table></figure></p><p>此时我们可以在source/_posts文件夹下面看到一个title.md的文件夹,通过markdown来编辑文章<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: Hello World #文章标题</span><br><span class="line">date: 2016-04-27 11:47:51 #创建时间</span><br><span class="line">tags: 初衷 #标签</span><br><span class="line">categories: 生活 #分类</span><br><span class="line">---</span><br><span class="line">content #文章内容</span><br></pre></td></tr></table></figure></p><p>文章写完后,通过如下命令发布:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure></p><p>over!!!不需要写一行代码,分分钟构建一个高大上的博客系统,是不是屌屌的?赶紧去试试。</p>]]></content>
<summary type="html">
<h2 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h2><p>花1分钟想想我们的目标:博客,它有自己独立的域名,有一个能存放我们的博客html文件的地方,然后我们也需要一套比较快速且高效的博客框架来迅速搭建我们的博客,让我们能很方便的排版布局,发布内容,定义样式甚至是切换主题。</p>
<p>基于以上需求,业界已经有非常成熟的解决方案了:Hexo+Github Pages</p>
<p>接下来,跟着tom一起,step by step无门槛的完成搭建博客之旅吧。<br></p>
</summary>
<category term="技术" scheme="http://lightom.cc/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Hexo" scheme="http://lightom.cc/tags/Hexo/"/>
<category term="Github Pages" scheme="http://lightom.cc/tags/Github-Pages/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="http://lightom.cc/2016/04/27/hello-world/"/>
<id>http://lightom.cc/2016/04/27/hello-world/</id>
<published>2016-04-27T03:47:51.000Z</published>
<updated>2016-04-28T10:34:19.000Z</updated>
<content type="html"><![CDATA[<h2 id="初衷"><a href="#初衷" class="headerlink" title="初衷"></a>初衷</h2><p>本人码农一枚,09年毕业至今,主要工作都是做安卓开发,但是从15年开始,特别是最近一段时间,越来越感觉到客户端和前端有融合的趋势,感到自己所学知识面的狭窄,所以抽时间自学了iOS和Web方面的知识。</p><p>前几天毛遂自荐的做完一个H5的小项目,做完后想复习下前端方面的知识,看了不少前端大牛都有属于自己的技术博客,一时手痒,买了域名,申请了github账号,利用hexo和github来搭建自己的博客。<br><a id="more"></a><br>博客跑起来后,俨然有了一个专属于自己的小天地,一个自己的小标签,我准备在这里记一些技术博文,自己的技术生涯和感悟,顺便记录下自己对生活的感悟。</p><p>相信以后想起这段经历,自己会感到开心。</p><p>下一篇博文我想介绍下自己搭建博客的过程:Step by Step 构建你自己的博客</p>]]></content>
<summary type="html">
<h2 id="初衷"><a href="#初衷" class="headerlink" title="初衷"></a>初衷</h2><p>本人码农一枚,09年毕业至今,主要工作都是做安卓开发,但是从15年开始,特别是最近一段时间,越来越感觉到客户端和前端有融合的趋势,感到自己所学知识面的狭窄,所以抽时间自学了iOS和Web方面的知识。</p>
<p>前几天毛遂自荐的做完一个H5的小项目,做完后想复习下前端方面的知识,看了不少前端大牛都有属于自己的技术博客,一时手痒,买了域名,申请了github账号,利用hexo和github来搭建自己的博客。<br></p>
</summary>
<category term="生活" scheme="http://lightom.cc/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="初衷" scheme="http://lightom.cc/tags/%E5%88%9D%E8%A1%B7/"/>
</entry>
</feed>