——欢迎转载,请注明出处 http://blog.csdn.net/asce1885 ,未经本人同意请勿用于商业用途,谢谢——

原文链接:https://github.com/futurice/android-best-practices

本文是Futurice公司的Android开发人员总结的最佳实践,遵循这些准则可以避免重复制造轮子。如果你对iOS或者Windows Phone开发感兴趣,那么也请看看iOS最佳实践Windows客户端开发最佳实践

概要

**使用Gradle和推荐的工程结构 **

**把密码和敏感数据存放在gradle.properties文件中 **

**不要自己实现HTTP客户端,要使用Volley或者OkHttp库 **

**使用Jackson库来解析JSON数据 **

**避免使用Guava,使用少量的函数库从而避免超出65k方法数限制 **

**使用Fragments来表示UI界面 **

**Activities只用来管理Fragments **

**布局XML文件是代码,要组织好它们 **

**使用样式文件来避免布局XML文件中属性的重复定义 **

**使用多个样式文件避免单一大样式文件的使用 **

**保持colors.xml文件简短和不重复,只定义颜色值 **

**保持dimens.xml文件不重复,并只定义通用的常量 **

**避免ViewGroups层次结构太深 **

**避免在客户端侧处理WebViews,谨防内存泄漏 **

**使用Robolectric作为单元测试的工具,Robotium作为UI测试的工具 **

**使用Genymotion作为你的模拟器 **

总是使用ProGuard或者DexGuard

**Android SDK **

把你的Android SDK目录放在电脑的主目录或者其他跟IDE安装目录独立的磁盘位置,某些IDE在安装时就包含了Android SDK,而且可能把它放在跟IDE相同的目录下。当你需要升级(或重新安装)IDE,或者更换IDE时,这种做法是不好的。同样要避免把Android SDK放在另外一个系统层级的目录中,这样当你的IDE在user模式下运行而不是root模式时,将需要sudo权限。

**构建系统 **

当下最受推崇的IDE是Android Studio,因为它是Google开发的,和Gradle耦合最好,默认使用最新的工程结构,已经处于稳定阶段,是为Android开发量身定做的IDE。

当然你也可以使用Eclipse ADT,但你需要配置它才能使用Gradle,因为它默认使用的是旧的工程结构和使用Ant进行构建。你甚至可以使用类似Vim,Sublime Text,Emacs等文本编辑器,这种情况下你需要在命令行中使用Gradle和adb。如果你的Eclipse集成Gradle不可用,你的选择是要么使用命令行编译或者把项目迁移到Android Studio中。Android Studio是最好的选择,因为ADT插件已经被标记为过时了,也就是不会再作后续维护和更新了。

无论你使用哪种方式,需保证的是按照官方的推荐使用新的工程结构和Gradle来构建你的应用,并避免把你特定于编辑器的配置文件加入到版本控制系统中。例如要避免把Ant的build.xml文件添加到版本控制系统中。特别是如果你在Ant中更改了编译配置,不要忘了同步更新build.gradle文件。最后一点,要对其他开发人员友好,不要迫使他们修改他们所用编辑器的偏好设置。

函数库

Jackson是一个把Java对象转换为JSON字符串或者把JSON字符串转换成Java对象的Java函数库。Gson也是解决这类问题很流行的选择之一,但我们发现Jackson更加高性能,因为它支持多种可选的处理JSON的方式:流,内存树模型和传统的JSON-POJO数据绑定。尽管如此,Jackson是比Gson更大的函数库,所以需要根据你项目的具体情况,你可能会选择GSON来避免65k方法数限制。其他的选择还有:Json-smartBoon JSON

**网络,缓存和图像。**向后端服务器发起网络请求有很多经过实战检验的解决方案,你应该使用这些解决方案而不是自己实现一个。使用Volley或者Retrofit吧!除了网络请求,Volley还提供了帮助类用于加载和缓存图像。如果你选择Retrofit,那么可以考虑使用Picasso作为加载和缓存图像的函数库,并结合OkHttp实现高效的HTTP请求。Retrofit,Picasso和OkHttp这三款函数库都是同一家公司开发的,所以它们能够很好的互补。Volley也能使用OkHttp来实现网络连接

RxJava是一个响应式编程的函数库,也就是可以处理异步事件。这是一个强大和有前途的编程范式,但由于它是如此的不同,因此会显得不好理解。在使用这个函数库搭建你的应用的框架时,我们建议你要保持谨慎的态度。我们有几个项目已经使用RxJava来实现,如果你需要帮助可以联系以下这些人:Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen。我们已经写了一些博客文章来进行介绍

1)http://blog.futurice.com/tech-pick-of-the-week-rx-for-net-and-rxjava-for-android

2)http://blog.futurice.com/top-7-tips-for-rxjava-on-android

3)https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

4)http://blog.futurice.com/android-development-has-its-own-swift)。

如果你之前没有使用RxJava的经验,那么开始时可以仅在网络请求API的响应处使用。如果有经验了,可以将RxJava应用在简单UI事件的处理,例如点击事件或者搜索框中的输入事件。如果你对自己的RxJava技能很自信而且想把RxJava应用到整个项目架构中,那么在代码难以理解的部分要编写Javadocs。要记住对RxJava不熟悉的程序员可能在维护工程的初期会很痛苦。尽你所能帮助他们理解你的代码和RxJava。

Retrolambda是兼容在Android中和JDK8之前的Java版本中使用Lambda表达式语法的一个Java函数库。它帮助你的代码保持紧凑和可读,特别是当你使用函数式编程风格时,例如使用RxJava。要使用这个库,需要安装JDK8,在Android Studio工程结构对话框中设置SDK的位置,并设置JAVA8_HOME和JAVA7_HOME环境变量,然后在工程的build.gradle中设置如下:

 

接着在各个模块的build.gradle中增加配置如下:

Activities and Fragments

因此,很难严格界定Fragments(或者Activities)是controllers类还是views类。最好把Fragments类单独放在fragments包里面。如果你遵循前面段落的建议的话(只有一个主Activity),Activities可以放在顶层的包里面。如果你计划会存在多个activities,那么就将Activity放在单独的activities包里面。

另一方面,整个包结构看起来很像经典的MVC框架,models包目录存放网络请求API响应经过JSON解析器填充后得到的POJOs对象。views包目录存放自定义的views,notifications,action bar views,widgets等等。Adapters处于灰色地带,介于data和views之间,然而,它们一般需要通过getView()函数导出视图,所以你可以在views包中增加adapters子包。

**命名。**遵循以类型作为前缀命名的惯例,即type_foo_bar.xml。例子如下:fragment_contact_details.xml,view_primary_button.xml,activity_main.xml。

    <TextView           android:id="@+id/name"           android:layout_width=“match_parent”           android:layout_height=“wrap_content”           android:layout_alignParentRight=“true”           android:text="@string/name"           style="@style/FancyText"           />  

    <include layout="@layout/reusable_part" />  

</LinearLayout>

**把一个大的style文件细分成多个文件。**你没有必要维护单独一个styles.xml文件,Android SDK能很好的支持其他文件。styles文件的名字并不一定要是styles.xml,起作用的是xml文件里面的<style>标签。因此,你的样式文件命名可以是styles.xml,styles_home.xml,styles_item_details.xml,styles_forms.xml等。和资源目录名不同(编译系统需要根据资源目录名找到资源),res/values里面的文件名可以随意命名。

colors.xml是调色板。在你的colors.xml文件中除了定义颜色名字到RGBA颜色值的映射外,不应该定义其他的东西。不用使用它来定义不同类型按钮的RGBA颜色值。

    <!– grayscale –>       <color name=“white”     >#FFFFFF</color>       <color name=“gray_light”>#DBDBDB</color>       <color name=“gray”      >#939393</color>       <color name=“gray_dark” >#5F5F5F</color>       <color name=“black”     >#323232</color>  

    <!– basic colors –>       <color name=“green”>#27D34D</color>       <color name=“blue”>#2A91BD</color>       <color name=“orange”>#FF9D2F</color>       <color name=“red”>#FF432F</color>  

</resources>

**dimens.xml文件跟colors.xml文件具有相同的用法。**你应该定义一个典型的间距和字体大小的模版,目的基本上和colors.xml文件一样,好的dimens.xml文件例子如下:

 

布局文件的边距和填充应该使用spacing_****尺寸定义,而不是使用硬编码(类似字符串硬编码)。这样会带来统一的外观,同时使得组织和修改样式和布局更简单。

**避免过深的views层级。**有时你可能会被诱导在LinearLayout中再增加一层LinearLayout,例如为了完成一组views的排列。这种情况类似如下:

即使你没有很明显的在Layout文件中看到这种情况,但可能最终发生在Java代码中将某个view inflate到另外的view中。

这可能会引起一些问题,你可能会遇到性能问题,因为处理器需要处理很复杂的UI树层级。另一个更严重的问题是可能会引起StackOverflowError

因此,尽量使你的view具有扁平的层级:学习怎样使用RelativeLayout,怎样优化布局和使用<merge>标签

**小心WebView相关的问题。**当你需要展示一个web页面时,例如新闻文章,要避免在客户端侧对HTML进行简化处理,相反,应该向服务器端请求经过简化后的HTML。当WebView持有所在Activity Context引用而不是Application Context引用时,也可能导致内存泄漏。要避免在简单文本或者按钮使用WebView,应该使用TextView和Button。

测试框架

Android SDK的测试框架还很简单,尤其是UI测试相关的。Android Gradle目前实现了一个叫做connectedAndroidTest的测试任务,它能够使用JUnit的Android扩展来运行你创建的JUnit测试用例。这意味着你需要连接设备或者模拟器来运行测试用例,遵循官方帮助指南来进行测试1)http://developer.android.com/tools/testing/testing_android.html

2)http://developer.android.com/tools/testing/activity_test.html)。

**使用Robolectric来进行单元测试,而不是UI测试。**这是一个为了提高开发速度,专注于提供“独立于设备”的测试框架,尤其适用于models和view models的单元测试。但是Robolectric对于UI测试的支持是不准确和不完善的。使用Robolectric进行动画,对话框等相关的UI元素测试时会遇到问题,你将看不到屏幕相应的UI元素被测试实时操纵,你将类似于在黑暗中行走。

Robotium简化了UI测试。你不需要Robotium来执行UI测试用例,但它提供了很多帮助工具用来获取和分析views,控制屏幕等,这一点对你可能很有帮助。测试用例很简单,如下所示:

模拟器

如果你的工作是开发android app,那么买一个Genymotion模拟器的licence吧。Genymotion模拟器比AVD模拟器具有更快的帧率,而且具有演示app,模拟网络连接质量,GPS位置等工具。它也是用于连接测试的理想工具。使用Genymotion模拟器,你可以模拟很多不同类型的设备,所以购买一个Genymotion模拟器licence比买多个真实设备更划算。

要注意的是:Genymotion模拟器没有移植所有的Google服务,例如Google Play Stoe和Google Maps。你可能需要测试三星特有的API,这时需要购买一台真实的三星设备。

Proguard配置

在Android工程中ProGuard被用于压缩和混淆打包后的代码。ProGuard的使用可以在工程配置文件中设置。一般情况下当构建一个release版本的apk时,你需要配置Gradle使用ProGuard。

为了决定哪些代码需要保留,哪些代码需要丢弃或者混淆,你需要在你的代码中指定一个或者多个入口点。这些入口点典型的就是具有main函数,applets,midlets,activities等的类。Android框架使用的默认配置文件是SDK_HOME/tools/proguard/proguard-android.txt。自定义的工程特有的proguard规则文件定义为my-project/app/proguard-rules.pro,将会拼接到默认配置中。

在你的项目早期,执行一个release构建来检查ProGuard规则是否正确的保持了不需要移除或者混淆的东西。当你增加新的函数库,也要执行新的Release构建并在设备上测试生成的apk来确保没有问题。不要等到你的app要发布1.0版本了才想到要执行一个release构建,这时你可能会得到及其不愉快的惊喜,并花一段时间来修复这些问题。

贴士:保存每个你发布给最终用户的apk包对应的mapping.txt文件。保存mapping.txt的原因在于当你的用户上传混淆过的crash日志时,你可以很容易的进行调试。

DexGuard:如果你需要能对你发布的代码进行优化,尤其是混淆的核心工具的话,可以考虑DexGuard,这是由ProGuard同一团队发布的商业软件。它还可以很容易的对分割Dex文件以解决65k函数个数限制问题。