原文链接:https://github.com/futurice/android-best-practices
转载来源:http://blog.csdn.net/asce1885/article/details/43699715
本文是Futurice公司的Android开发人员总结的最佳实践,遵循这些准则可以避免重复制造轮子。如果你对iOS或者Windows Phone开发感兴趣,那么也请看看iOS最佳实践(https://github.com/futurice/ios-good-practices)和Windows客户端开发最佳实践(https://github.com/futurice/win-client-dev-good-practices)。
概要
使用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权限。
构建系统
工程结构
old-structure
├─ assets
├─ libs
├─ res
├─ src
│ └─ com/futurice/project
├─ AndroidManifest.xml
├─ build.gradle
├─ project.properties
└─ proguard-rules.pro
新的工程结构如下所示:
new-structure
├─ library-foobar
├─ app
│ ├─ libs
│ ├─ src
│ │ ├─ androidTest
│ │ │ └─ java
│ │ │ └─ com/futurice/project
│ │ └─ main
│ │ ├─ java
│ │ │ └─ com/futurice/project
│ │ ├─ res
│ │ └─ AndroidManifest.xml
│ ├─ build.gradle
│ └─ proguard-rules.pro
├─ build.gradle
└─ settings.gradle
主要的区别在于新的结构明确的区分源码集合(main和androidTest),这是从Gradle引入的概念。例如,你可以在源码目录src中添加paid和free两个子目录,分别用来存放付费版和免费版app的源码。
signingConfigs {
release {
storeFile file("myapp.keystore")
storePassword "password123"
keyAlias "thekey"
keyPassword "password789"
}
}
你应用创建一个gradle.properties文件,该文件不要添加到版本控制系统中,并设置如下:
KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789
gradle会自动导入这个文件,现在你可以在build.gradle中这样使用:
signingConfigs {
release {
try {
storeFile file("myapp.keystore")
storePassword KEYSTORE_PASSWORD
keyAlias "thekey"
keyPassword KEY_PASSWORD
}
catch (ex) {
throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
}
}
}
优先选择Maven依赖而不是导入jar文件。如果你在工程中显式地包含jar文件,它们会是特定的不可变的版本,例如2.1.1。下载jar包并手动更新是很麻烦的,而这个问题Maven正好帮我们解决了,在Android Gradle构建中也建议这么做。你可以指定某个版本范围的jar包,例如2.1.+,这样Maven会帮我们自动更新和这个版本模式匹配的后续升级。例子如下:
dependencies {
compile 'com.netflix.rxjava:rxjava-core:0.19.+'
compile 'com.netflix.rxjava:rxjava-android:0.19.+'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.+'
compile 'com.fasterxml.jackson.core:jackson-core:2.4.+'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.+'
compile 'com.squareup.okhttp:okhttp:2.0.+'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.+'
}
IDE和文本编辑器
当下最受推崇的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(http://wiki.fasterxml.com/JacksonHome)是一个把Java对象转换为JSON字符串或者把JSON字符串转换成Java对象的Java函数库。Gson(https://code.google.com/p/google-gson/)也是解决这类问题很流行的选择之一,但我们发现Jackson更加高性能,因为它支持多种可选的处理JSON的方式:流,内存树模型和传统的JSON-POJO数据绑定。尽管如此,Jackson是比Gson更大的函数库,所以需要根据你项目的具体情况,你可能会选择GSON来避免65k方法数限制。其他的选择还有:Json-smart(https://code.google.com/p/json-smart/)和Boon JSON(https://github.com/RichardHightower/boon/wiki/Boon-JSON-in-five-minutes)。
网络,缓存和图像。向后端服务器发起网络请求有很多经过实战检验的解决方案,你应该使用这些解决方案而不是自己实现一个。使用Volley(https://android.googlesource.com/platform/frameworks/volley)或者Retrofit(http://square.github.io/retrofit/)吧!除了网络请求,Volley还提供了帮助类用于加载和缓存图像。如果你选择Retrofit,那么可以考虑使用Picasso(http://square.github.io/picasso/)作为加载和缓存图像的函数库,并结合OkHttp(http://square.github.io/okhttp/)实现高效的HTTP请求。Retrofit,Picasso和OkHttp这三款函数库都是同一家公司开发的,所以它们能够很好的互补。Volley也能使用OkHttp来实现网络连接(http://stackoverflow.com/questions/24375043/how-to-implement-android-volley-with-okhttp-2-0/24951835#24951835)。
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(https://github.com/evant/gradle-retrolambda)是兼容在Android中和JDK8之前的Java版本中使用Lambda表达式语法的一个Java函数库。它帮助你的代码保持紧凑和可读,特别是当你使用函数式编程风格时,例如使用RxJava。要使用这个库,需要安装JDK8,在Android Studio工程结构对话框中设置SDK的位置,并设置JAVA8_HOME和JAVA7_HOME环境变量,然后在工程的build.gradle中设置如下:
dependencies {
classpath 'me.tatarka:gradle-retrolambda:2.4.+'
}
接着在各个模块的build.gradle中增加配置如下:
apply plugin: 'retrolambda'
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
retrolambda {
jdk System.getenv("JAVA8_HOME")
oldJdk System.getenv("JAVA7_HOME")
javaVersion JavaVersion.VERSION_1_7
}
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子包。
com.futurice.project
├─ network
├─ models
├─ managers
├─ utils
├─ fragments
└─ views
├─ adapters
├─ actionbar
├─ widgets
└─ notifications
资源
命名。遵循以类型作为前缀命名的惯例,即type_foo_bar.xml。例子如下:fragment_contact_details.xml,view_primary_button.xml,activity_main.xml。
使用styles。几乎所有工程都需要正确的使用styles,因为它是让view具有相同外观的常见的方法。你的应用的文本内容应该至少具有一个公用的样式,例如:
用在TextView上面如下:
你可能需要对buttons做类似的工作,但别就此停住。继续把相关的和重复的android:****属性分组到公用的style文件中。
把一个大的style文件细分成多个文件。你没有必要维护单独一个styles.xml文件,Android SDK能很好的支持其他文件。styles文件的名字并不一定要是styles.xml,起作用的是xml文件里面的