曾经一直想写一篇总结 Android 开发经验的文章,预计当时的我还达不到某种水平,因此思路跟不上,下笔又捉襟见肘。近日,思路较为明朗。因而又一次操起键盘開始码字一番。java
先声明一下哈,本人不是大厂的程序员。去年毕业前。就一直在当前创业小团队从事本身热爱的打码事业至今。如下总结是创建在我当前的技术水平和认知上写的,若有不一样见解欢迎留下评论互相交流。android
眼下 Android 平台上绝大部分开发都是用着 Java ,而跟 Java 这样一门面向对象的语言打交道。难免要触碰到 抽象 和 封装 的概念。我身边接触过的一些开发人员。有一部分还对这些概念停留在写一个抽象类、接口、或者一个方法(或抽象方法)。git
至于为何。我不大清楚是他们表达不出来,仍是不理解。程序员
如下我也不高谈阔论,直接举样例来解释我所理解的抽象。github
//Activity 间使用 Intent 传递数据的两种写法 如下均是伪代码形式。请忽略一些细节
//写法一
//SrcActivity 传递数据给 DestActivity
Intent intent = new Intent(this,DestActivity.class);
intent.putExtra("param", "clock");
SrcActivity.startActivity(intent);
//DestActivity 获取 SrcActivity 传递过来的数据
String param = getIntent.getStringExtra("param");
//写法二
//SrcActivity 传递数据给 DestActivity
Intent intent = new Intent(this,DestActivity.class);
intent.putExtra(DestActivity.EXTRA_PARAM, "clock");
SrcActivity.startActivity(intent);
//DestActivity 获取 SrcActivity 传递过来的数据
public final static String EXTRA_PARAM = "param";
String param = getIntent.getStringExtra(EXTRA_PARAM);
写法一。存在的问题是,假设 SrcActivity 和 DestActivity 哪一个把 "param" 打错成 "para" 或者 "paran" 。传递的数据都没法成功接收到。而写法二则不会出现此类问题,因为两个 Activity 之间传递数据仅仅需要知道 EXTRA_PARAM 变量就能够。至于 EXTRA_PARAM 变量到底是 "param" 、 "para" 、"paran" 这一点并不需要关心,这就是一种对可能发生变化的地方进行抽象封装的体现。它所带来的优势就是减小手抖出错的几率,同一时候方便咱们进行改动。数据库
基于抽象和封装,Java 自己很是多 API 在设计上就有这种体现,如 Collections 中的很是多排序方法:编程
这些方法都是基于 List 这个抽象的列表接口进行排序。至于这是一个用什么样的数据结构实现 List(ArrayList 仍是 LinkedList),排序方法自己并不关心。看,是否是体现了 JDK 的设计人员的一种抽象编程的思惟,因为 List 的详细实现可能有千万种。假设每一类 List 都要写一套排序方法,预计要哭瞎了。json
小结:把easy出现变化的部分进行抽象,就是对变化的一种封装。api
一个项目的开发。咱们不可能一切从0作起,假设真是这样,那相同要哭瞎。缓存
所以,善于借用已经作好的 "车轮" 很重要,如:
网络訪问框架:okhttp、retrofit、android-async-http、volley
图片载入框架:Android-Universal-Image-Loader、Glide、Fresco、Picasso
缓存框架:DiskLruCache、 Robospice
Json解析框架:Gson、Fastjson、Jackson
事件总线:EventBus、Otto
ORM框架:GreenDAO、Litepal
还有其它各类各样开源的本身定义控件、动画等。除了以上提到的开源框架,也包含一些不开源的SDK
数据统计:友盟统计,百度统计...
奔溃搜集:腾讯bugly、bugtags...
云存储:七牛...
即便通信:环信、融云、阿里百川...
推送:小米推送、腾讯推送、百度推送...
安全加固:360加固宝、爱加密...
普通状况下,我在选择是否引入一些开源框架主要基于下面几个因素:
大神和大公司出品的框架质量相对较高。可保证兴许的维护和bug修复,不easy烂尾;
针对不开源SDK的选择,也主要基于下面几点去考虑:
诸如。友盟官网:
好的SDK。使用文档确定会具体指引你。出了问题。上开发人员社区提问,他们的开发project师也会社区上回答。实在不行仅仅能联系客服,假设客服的态度都让你不爽,那就可以考虑换别家的SDK了。
小结:选好 "车轮" 。事半功倍
为何要抽象依赖于第三方框架呢?这里和第1点是互相照顾的,就是减小咱们对详细某个框架的依赖性,从而方便咱们高速切换到不一样的框架去。讲到这里,你可能认为很是抽象。那我直接举一个载入图片的样例好了。
若是你当前为项目引入一个载入图片的框架 —— Android-Universal-Image-Loader,最简单的作法就是增长对应的依赖包后。在不论什么需要载入图片的地方写上如下这种代码段。
ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view
// which implements ImageAware interface)
imageLoader.displayImage(imageUri, imageView);
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// Do whatever you want with Bitmap
}
});
这种作法最简单粗暴,但是带来的问题也最严重的。假设我有几十上百个地方都这么写,而在某一天。我据说Facebook出了个神器 Fresco。想要换掉 Android-Universal-Image-Loader ,你就会发现你需要丧心病狂的去修改几十上百个地方的代码,不只工做量大,而且还easy出错。形成这种缘由,就在于项目和载入图片的框架之间造成了强耦合。而实际上,项目自己不该该知道我详细用了哪一个载入图片的框架。
正确的方式,应该是对框架作一个抽象的封装。以应对将来发生的变化。我直接举本身的开源项目 AndroidAlbum 中的一种封装作法好了。
大体代码例如如下:
//一、声明 ImageLoaderWrapper 接口,定义一些抽象的载入接口方法
public interface ImageLoaderWrapper {
/** * 显示 图片 * * @param imageView 显示图片的ImageView * @param imageFile 图片文件 * @param option 显示參数设置 */
public void displayImage(ImageView imageView, File imageFile, DisplayOption option);
/** * 显示图片 * * @param imageView 显示图片的ImageView * @param imageUrl 图片资源的URL * @param option 显示參数设置 */
public void displayImage(ImageView imageView, String imageUrl, DisplayOption option);
/** * 图片载入參数 */
public static class DisplayOption {
/** * 载入中的资源id */
public int loadingResId;
/** * 载入失败的资源id */
public int loadErrorResId;
}
}
// 二、将 UniversalAndroidImageLoader 封装成继承 ImageLoaderWrapper 接口的 UniversalAndroidImageLoader ,
//这里代码有点长,感兴趣可以查看项目源代码中的实现 https://github.com/D-clock/AndroidAlbum
// 三、作一个ImageLoaderFactory
public class ImageLoaderFactory {
private static ImageLoaderWrapper sInstance;
private ImageLoaderFactory() {
}
/** * 获取图片载入器 * * @return */
public static ImageLoaderWrapper getLoader() {
if (sInstance == null) {
synchronized (ImageLoaderFactory.class) {
if (sInstance == null) {
sInstance = new UniversalAndroidImageLoader();//<link>https://github.com/nostra13/Android-Universal-Image-Loader</link>
}
}
}
return sInstance;
}
}
//四、在所有需要载入图片的地方做例如如下的调用
ImageLoaderWrapper loaderWrapper = ImageLoaderFactory.getLoader();
ImageLoaderWrapper.DisplayOption displayOption = new ImageLoaderWrapper.DisplayOption();
displayOption.loadingResId = R.mipmap.img_default;
displayOption.loadErrorResId = R.mipmap.img_error;
loaderWrapper.displayImage(imagview, url, displayOption);
这样一来,切换框架所带来的代价就会变得很是小,这就是不直接依赖于框架所带来的优势。固然,以上仅仅是我比較简单的封装,你也可以进行更加仔细的处理。
小结:预留变动,不强耦合于第三方框架
说实话,在没接触 MVP 的架构以前,一直都是使用 MVC 的模式进行开发。
而随着项目愈来愈大。Activity或者 Fragment里面代码愈来愈臃肿,看的时候想吐,改的时候想屎...这里撇开其它各类各样的架构不谈,仅仅对照MVC 和 MVP 。
你会发现,假设 View 层仅仅包括了xml文件,那咱们 Android 项目中对 View 层可作操做的程度并不大。顶多就是用include复用一下布局。
而 Activity 等简直就是一个奇葩,它尽管归属于 Controller 层,但实际上也干着 View 层的活(View 的初始化和相关操做都是在Activity中)。就是这样的既是 View 又是 Controller 的结构,违背了单一责任原则。也使得 Activity 等出现了上述的臃肿问题。
相比 MVC,MVP在层次划分上更加清晰了,不会出现一人身兼二职的状况(有些单元測试的童鞋,会发现单元測试用例更好写了)。在此处你可以看到 View 和 Model 之间是互不知道对方存在的,这样应对变动的优势更大。很是多时候都是 View 层的变化,而 Model 层发生的变化会相对较少,遵循 MVP 的结构开发后。改起来代码来也没那么蛋疼。
这里也有地方需要注意,因为大量的交互操做集中在 Presenter 层中,因此需要把握好 Presenter 的粒度。一个 Activity 可以持有多个 View 和 Presenter。这样也就可以避开一个硕大的 View 和 Presenter 的问题了。
推荐两个不错的 MVP 架构的项目给你们。还不明确的童鞋,可以自行体会一下其设计思想:
https://github.com/pedrovgs/EffectiveAndroidUI
https://github.com/antoniolg/androidmvp
小结:去加以实践的理解 MVP 吧
把一些常用的工具类或业务流程代码进行归类整理。增长本身的代码库(尚未本身我的代码仓库的童鞋可以考虑建一个了)。如加解密、拍照、裁剪图片、获取系统所有图片的路径、本身定义的控件或动画以及其其它他一些常用的工具类等。
归档有助于提升你的开发效率,在遇到新项目的时候随手就能够引入使用。假设你想要更好的维护本身的代码库,最好仍是在不泄露公司机密的前提下。把这个私人代码库加上具体文档给开源出去。这样可以吸引不少其它开发人员来使用这些代码,也可以得到对应的bug反馈,以便于着手定位修复问题。加强这个仓库代码的稳定性。
小结:合理归档代码,可以的话。加以开源维护
关于性能优化的问题。大致都仍是关注那几个方面:内存、CPU、耗电、卡顿、渲染、进程存活率等。
对于这些地方的性能优化思路和分析方法,网络上已经有很是多答案了。此处不作赘述。
我仅仅想说下面几点:
毕竟老板问你比曾经耗电减小多少,总不能回答减小了一些吧?
?
?
小结:合理优化,数据量化
Rxjava、React Native、Kotlin...開始兴起后。身边有很是多开发人员会跟风直上。学习新技术的精神是很是值得鼓舞的,但没有通过一段时间实践观察,就擅自把新技术引入到商业项目中,则有失稳当。对于大公司的团队来讲,会有专门团队或项目去研究这些新兴技术。以肯定是否在本身的产品线开发中引入。
但做为小公司,是否是就意味着没有实践尝试新技术的机会呢?并不是!
我的有下面几点建议:
实践新技术的过程尽可能加以具体的文档记录,这会有助于减小项目组其它同事对新技术的入门门槛,可以的话,也将学习文档开源,得到不少其它开发人员对此份文档的反馈,也可纠正一些文档中的错误。
所有新技术的引入都要考虑是否符合当下的业务需求,我听过有些程序员想引入新技术的缘由是因为认为这样的技术很是酷。网上说很是好用。很是啥啥啥...本身全然没弄过就人云亦云。有时候好无语,感受在会用一些技术就像在炫技同样;
小结:空谈误国,实干兴邦
UML,驯服代码和了解项目结构的利器,本人也在学习和体验其优势的路途上。不管遇到大小项目,有了它,可以更好的理清一些脉络结构。对付旧的庞大项目代码。或者有志阅读某些开源项目代码的开发人员。绝对是居家必备。
小结:工欲善其事,必先利其器
前面 2 提到,项目不可能从0開始,是需要引入很是多第三方框架的。这里并不与 2 互相违背。而是建议有想提升技术逼格的开发人员,可以在空闲时间去编码实现一个框架。假设你对网络訪问、图片载入方面很是有研究看法。最好仍是把这些脑海里的思想落实成详细的代码。或许你会发现。你动手去实践的时候。考虑的东西会多得多,本身终于获得的也会不少其它。
(特别建议那些看过很是多开源码。又至今未本身动手自撸一发的)
小结:不要停留在 api 调用的层面
有空又经济能力承受得起的时候,最好仍是去參加一些本身感兴趣的技术交流会。很是多都有大牛上台演讲。听听人家的解决方式,拓宽一下本身看问题的思路,也可以多參加一些含金量高的线上活动。
我有挺多开发人员朋友,就是參加活动的时候认识的,有时候遇到一些技术问题,还会互相探讨交换一下解决思路。
挺赞的!
小结:拓宽技术视野
这个可能没什么好说的,你们看了标题就懂了。它最大的优势在于:
小结:认真总结,不断无缺
程序员不要总是对着电脑。赶忙找个对象提高一下幸福感。听说幸福感高的程序员。编码效率高,出bug概率小...
总结:作个面向对象的程序猿
大概就想到这些了,之后要是再有想写的。另开新篇。絮絮不休写了这么多,最关键的仍是本身要落实,千万不要据说过太多道理,却依旧过很差这一辈子哈!
!!。