或许对于许多 Android 开发者来说,所谓的 Android 工程师的工作 “不过就是用 XML 实现设计师的美术图,用 JSON 解析服务器的数据,再把数据显示到界面上” 就好了,源码什么的,看也好不看也罢,反正应用层的开发用不上,再加上现在优秀的轮子越来越多,拿来主义泛滥,能用就是,反正老板也不关心是不是你自己写的,用我现在老大的话来说,阅读源码似乎只是一种 “锦上添花” 的事,有自然好,没有也罢。
那么,作为 Android 开发者的自我修养,到底有没有必要阅读 AOSP 以及其他开源项目的源码呢?
刚开始时候的故事
对于我来说,选择编程是因为我看见了 MoeLoader 这款收图应用实在是漂亮才开始写代码,我要的目的只是应用漂亮,不用在乎代码写成什么样,而且我觉得代码是我写的,这么辛苦的作品可不能白白开源给别人看。所以对于这个时候的我,那时候虽然没有考虑过类似的问题,但是很可能觉得阅读源码是没有必要的。
后来我开始学习 Android,原因非常简单,C# 根本无法找到合适的工作,而学生党我的我根本无法买得起苹果三套件,此外,IE6 的兼容工作让我实在是对前端敬而远之,所以选择只剩下 Android 了。说实在的,一开始我是不太喜欢 Android 开发,特别是 IDE 从 Visual Studio 切换到万恶的 Eclipse,丑,卡顿,动不动就找不到依赖,甚至有时候编译一直报红 Error,定位了半天找不到问题,到最后把红色的 Error 删除掉后居然就编译通过了!这时候的我,别说阅读源码了,我只求同一份代码在运行的时候有同样的逻辑就好。
再到后来,我已经有一些 Android 程序设计的经验了,IDE 也开始换到 Android Studio(Preview 版本刚出来的时候,我在 Android Studio 和 Eclipse 之间切换过好几次,不得不说习惯这种东西有时很有帮助,有时候也会很可怕),换到 Android Studio 很大一个原因是因为 Github 上面许多开源项目用 Android Studio 来部署很方便。这个时候我接触的开源项目已经比较多了,许多时候一些开源项目总有一些 BUG,我会给其提交 ISSUE,不过更多时候我不能等项目所有者来解决,需要我自己解决 BUG;许多时候开源项目并不能直接满足业务的需要,所以我也需要先阅读源码再改造成自己的项目能用的。
这里需要特别说明的是,我的第一份工作的项目是一个 SDK 项目,整体使用了基于 ClassLoader 的动态加载的框架。那时候还比较早,国外对动态加载不感兴趣,国内的话也只有零星的技术博客对这有讨论,不过大多是介绍如何实现动态加载而没有分析其工作机制。所以,当有新的技术需求,或者项目出现 BUG 的时候,我都需要自己阅读源码去解决问题。比如,有一次设计师需要一个全圆角的菜单背景,然而 Android 的点九图是 X 轴和 Y 轴都需要拉伸的,当 Y 轴拉伸的时候就无法实现全圆角。我能做的就是,先把点九图的原图等比缩放到 Y 轴填满,这样 Y 轴就不会被拉伸了,但是原图缩放后,点九图 X 轴的拉伸却出现了扭曲的样式。通过阅读 NinePatchDrawable 的源码,我发现点九图的原理就是一个普通的 Drawable 加上一个用于描述拉伸坐标的数组 chunk,当我缩放 Drawable 的时候,也必须更新 chunk,不然拉伸的坐标就对不上,后面通过阅读源码中关于 chunk 的描述,把对应的拉伸坐标更新后,全圆角的点九图 也就实现了。
为什么要阅读源码
说了这么多,到底有没有必要阅读源码?有必要,而且非常有必要!原因有三。
其一,了解基层,高层才能更好地工作。
比如,了解 View 的绘制过程,了解 TouchEvent 的分发和拦截过程的细节,才能写出酷炫的 UI,要不然,只知道大概的原理的话,你可能要在 “无法接收到触摸事件” 或者 “滑动事件和点击事件冲突” 的这些问题上折腾半天。
又比如,如果哪里出现异常,你能快速定位到源码抛异常类的地方,就能快速解决 BUG,对症下药,一招撂倒,有些时候,修复 BUG 的时间不是用在解决问题上,而是用在定位问题上。
这里有必要提一下,当 Logcat 把异常的栈信息打印出来的时候,有些异常出现的原因并不真的是 Logcat 的信息里描述的原因,因为 Logcat 里的异常的信息也只是由系统源码打印出来的,而这些源码大多时候只是普通的 Java 代码,和你自己写的没什么区别,如果源码抛出异常的代码的逻辑不够严谨的话,那实际的异常和 Logcat 里描述的异常可能对不上。比如之前搞动态加载的时候,在使用 LayoutInflator 渲染一个外部的 XML 布局时,抛了一个 “Class not found” 的异常,我要渲染的类可是 LinearLayout 啊,怎么可能没有!定位到源码里才发现,这里只要是类渲染失败就会抛这个异常,再定位到具体抛异常的地方,发现实际是 Dimens 资源找不到,困扰半年的问题立刻解决。
其二,能够理解 Android 设计者的意图。
这个描述可能不好,比如说,许多人都觉得 Android 开发其实就是 Java 开发,通过阅读 Context 类的设计,你能够理解 Google 是如何在 Java 的基础上加上 Android 的特性的,你能够理解 Context 被叫做 “环境” 的原因。此外,阅读 Activity/Service 的源码,你能理解到四大组件类明明就是普通的 JAVA 类,为什么他们就是组件而别的类就不是组件。阅读 Handler/Message/Looper 的源码,你还能理解到 Handler 的精髓,数据驱动比事件驱动更适合用于设计需要经常改动的框架。阅读源码,你能知道 Android 是怎么管理 Window 以及向控制 View 的触摸事件的,你能知道基本上所有的 res 资源都有等价的 Java 代码的实现方式,你还能知道 Dalvik 是怎么无缝向 ART 过度的,在看通的那一瞬间,保证你觉得“水可载舟,亦可赛艇”!
其三,能够学习优秀开源项目的代码风格和设计理念
这也是最重要的,看多了源码之后,你会发现所谓的源码也不过是普通的的 Java 代码,在不知不觉中受到这些优秀设计思想的影响。相信许多人在看 Volley 源码此前,对异步任务控制的想法基本就是毫无想法,看完之后简直是醍醐灌顶,原来代码也能写得这么有魅力,再看看自己之前写的异步任务,“new Thread().start”…,简直是 “too young, sometime naive” 有没有。
看了越来越多 Android 的源码,自己的写应用的时候,也就能写出更加 “Best Performance” 的代码,见识了越来越多的开源项目,自己也能够更容易找到最符合自己应用的框架和技术方案,学习了越来越多的优秀的代码风格,自己也就更能写出漂亮以及容易扩展的代码。
或许对许多做 Android 开发来说,平时的工作就是按照设计的图写个布局,再解析后台的数据,下班了把测试用的安卓机扔进抽屉拿出自己的苹果手机…… 但有时候花点时间看看源码,或许会觉得设计代码还是挺有意思的,特别是,当你花了两天的时间构思代码,再花两天的时间写代码,这时你可能觉得你还有许多代码要写,但是突然发现只要把你写好的接口衔接一下就都完成了,而且写了两天的代码居然一次编译通过!更甚,产品突然改了个需求,你在抱怨了一顿后发现只要花 10 分钟把原来的接口换个实现就搞定了,这或许是程序员工作中为数不多的乐趣吧。
最后,我想说的是,每个人对技术的追求不一样,有的人总是恨不得多知道一点,有的只需要日复一日地重复类似的码代码工作就足够了。所以,“需不需要阅读源码” 就是一个伪命题,对任何人来说答案都不太一样。不过,既然 Android 相比隔壁 iOS 最大的优势在于开源,如果你还在犹豫要不要阅读源码,我建议有时间还是稍微看看吧,万一就打开新世界的大门呢?
共同學習,寫下你的評論
評論加載中...
作者其他優質文章