[b]一、几句话
[/b]
[list]
[*]使用Gradle及其推荐的项目框架[/*]
[*]把密码等敏感数据放入gradle.properties[/*]
[*]不要自己写Http客户端,使用Volley或OkHttp库[/*]
[*]使用Jackson库来解析JSON数据[/*]
[*]避免[url=https://github.com/google/guava]Guava[/url]并出于[url=http://Dalvik%2065K%20methods%20limit]Dalvik 65K methods limit[/url]不要使用过多的库[/*]
[*]使用Fragment来绘制UI界面[/*]
[*]Activity主要用来管理Fragment[/*]
[*]布局文件XML也是代码,好好组织它们[/*]
[*]在布局文件里,使用styles以避免重复的属性[/*]
[*]使用多个style文件而不是一个巨大的style文件[/*]
[*]保持你的 color.xml 短小而DRY,定义色盘[/*]
[*]同样保持 dimens.xml DRY,定义通用常量[/*]
[*]不要创建一个太深层次的布局[/*]
[*]避免WebView的客户端处理,而且要注意内存泄露[/*]
[*]使用Robolectric来进行单元测试,Robotium来进行连接(UI)测试[/*]
[*]仿真器用Genymotion[/*]
[*]一定要用ProGuard 或 DexGuard[/*]
[/list]
[b]二、详细
Android SDK
[/b]把你的Android SDK放置在你的主目录里或其他与应用无关的地方。一些IDEs在安装的时候会把SDK关联上,并把SDK放在IDE的同一个目录下。当你需要升级(重装)IDE或者更换IDE时你就会发现糟糕之处啦。另外,如果你的IDE在一个user账户下而不是在root下运行的话,就不要把SDK放在系统级目录下,否则在使用时需要 sudo 权限,
[b]Build System
[/b]默认的选择是 [url=http://tools.android.com/tech-docs/new-build-system]Gradle[/url]。Ant限制比较多而且太大。使用Gradle,你可以很轻易的做到:
-编译不同的flavours 或应用的 variants
-创建简单的 类-脚本 任务
-管理和下载依赖
-自定义keystores
-等等
Android的Gradle插件同样被Google指定为新的标准编译系统,而且Google不断为其升级。
[b]项目结构
[/b]有两种流行的选择:旧的Ant & Eclipse ADT项目结构;新的Gradle & Android Studio项目结构。你应该选择后者。如果你的项目使用旧的结构,那么换掉吧。
旧结构
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的理念。
使用最高级别"app"有利于将你的app和其他你的应用所引用的库项目(如:library-foobar)做区分。然后settings.gradle保持应用对这些库的索引,而app/build.gradle可以指向这些库。
[b]Gradle配置
[/b]通用架构请遵循[url=http://tools.android.com/tech-docs/new-build-system/user-guide]Google's guide on Gradle for Android[/url];
小任务(脚本),你可以使用Gradle来制作小任务而不是Shell、Python或Perl等,具体参考[url=http://www.gradle.org/docs/current/userguide/userguide_single.html#N10CBF]Gradle's documentation[/url];
密码。在你应用的build.gradle中你需要为发布编译定义 signingConfigs。具体如下:
不要像下面这样写,这样会出现在你的版本控制系统里:
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")
storePasswordKEYSTORE_PASSWORD
keyAlias"thekey"
keyPasswordKEY_PASSWORD
} catch(ex) {
thrownewInvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
}
}}
(如果使用Maven可参考[url=https://github.com/futurice/android-best-practices]原文档[/url])
[b]库
[/b][url=http://wiki.fasterxml.com/JacksonHome]Jackson[/url]是一个Java库,它可以实现对象和JSON数据的相互转换。[url=https://code.google.com/p/google-gson/]Gson[/url] 也是一个类似的不错选择。不过我们觉得Jsckson更好因为它支持多种方式来处理JSON:流式,内存树模型和传动的JSON-POJO数据绑定。但是,记住,Jackson比GSON更加庞大,所以你要酌情考虑,如果你想避免 65k methods limit那最好用GSON。其他选择:[url=https://code.google.com/p/json-smart/]Json-smart [/url]和 [url=https://github.com/RichardHightower/boon/wiki/Boon-JSON-in-five-minutes]Boon JSON[/url]
网络、缓存和图片。使用[url=https://android.googlesource.com/platform/frameworks/volley]Volley[/url] 或者[url=http://square.github.io/retrofit/]Retrofit[/url]。Volley也可以用来加载和缓存图片。如果你选择Retrofit,你可以用[url=http://square.github.io/picasso/]Picasso[/url] 来加载和缓存图片。然后使用 [url=http://square.github.io/okhttp/]OkHttp[/url] 来执行有效的HTTP请求。这三种:Retrofit、Picasso和OkHttp都来源于同一样公司,所以它们互相补充。OkHttp 能用来与 Volley 相连接。
RxJava是一个响应式编程库,换句话说,处理异步事件。(具体可参考[url=https://github.com/futurice/android-best-practices]原文档[/url])
[url=https://github.com/evant/gradle-retrolambda]Retrolambda[/url] 是一个Java库,它帮助你的Android或者其他早于JDK8平台上使用Lambda表达式。(具体可参考[url=https://github.com/futurice/android-best-practices]原文档[/url])
最后,记住dex方法限制,不要使用太多库。(Android应用,当被打包成dex文件时,有一个最大限制:65535个引用方法[1][2][3]。如果你超过了限制就会发生严重错误。因此,不要使用刚过多库,使用 [url=https://github.com/mihaip/dex-method-counts]dex-method-counts [/url]工具来决定使用哪些类从而保持在限制内,尤其要避免使用Guava库,因为它包含超过13k方法)
[b]Activities和Fragments
[/b]Fragments应该是你在Android部署UI界面的默认选项。Fragments可以在你的应用里重用。我们推荐使用Fragements而不是 activities 来绘制界面基于以下几点:
[list]
[*]解决是多视图布局。Fragments被引入进来的主要原因是把手机应用程序拓展到平台电脑上,这样的话你在平板上可以同时显示A和B视图,而在手机上可只显示A或B。如果你的程序最开始就是使用Fragment来实现,那么你的程序可以更容易适用于多种设备。[/*]
[*]屏到屏的通信。Android的API并不提供一个合适的方式来实现Activity之间传递复杂数据(如Java对象)。但是,使用Fragment,你可以利用Activity来成为其子Fragment之间通信的通道。即使这比Activity-到-Activity通信要好不少,我仍然建议你采取Event Bus架构,例如使用Otto 或者 greenrobot EventBus来作为一个更简洁的方案。如果你不想采取附加的库,那么RxJava也可以被用来实现一个EventBus。[/*]
[*]Fragment不仅仅可以用来布局UI。你可以添加一个 没有UI界面的Fragment 作为Activity的后台服务者。甚至你可以创建一个Fragment来实现Fragment切换逻辑,而不是让Activity去处理Fragment切换逻辑。[/*]
[*]Fragment里甚至可以管理ActionBar。你可以选择一个没有UI界面的Fragment来专门管理ActionBar,或者你可以选择每个当前可视的Fragment自己来处理父Activity的ActionBar。参考这里。[/*]
[*]然后,我们也不建议过度使用嵌套Fragments,那可能导致matryoshka 漏洞。[/*]
[*]从架构的角度来考虑,你的应用应该有一个顶级Activity,它会包含大部分业务相关的fragments。你也可以创建一些其他的支持性Activities,只要它们与主Activity的通信保持简单--形似与 Intent.setData()或Intent.setAction()。[/*]
[/list]
[b]Java包结构[/b]
在Android应用程序里的Java结构接近MVC结构(Model-View-Controller)。在Android里,Fragment和Activity实际上都是控制器类。而从另一角度来看,他们又是用户交互的一部分,也就是说属于视图View类。
因此,我们很难严格区分Fragment(或Activity)是控制器还是视图。所以从Java包角度来看,我们最好把Fragment放在它们自己的fragments包里,然后Activity放在最高级的包里面(遵循上文提出的建议)。当然,如果你想有2个或以上的Activity,那你就创建一个activitys包。
这样的话,整个结构看起来就是一个典型的MVC结构。一个Models包包含POJOs,用来转化API接口获取的Json数据,一个views包包含Views,notifications,action bar views,widgets等。Adapters是一个中间层,位于数据和视图之间。但是,它们通常需要通过getView()来输出View视图,所以你可以把adapters放在views包的子包位置。
一些应用程序级别、仅属于Android系统的控制器类,应该放在managers包里。各种各样的数据处理类,例如DateUtils可以放在utils包里。与后台服务器交互的类应该放在network包里。
总之,从与服务器交互到与用户交互的整体架构可设计如下:
com.futurice.project
├─ network
├─ models
├─ managers
├─ utils
├─ fragments
├─ views
├─ adapters
├─ actionbar
├─ widgets
├─ notifications
[b]资源文件
命名
[/b]遵循加前缀的惯例,类似type_foo_bar.xml,如:fragment_contact_details.xml,view_primary_button.xml,activity_main.xml。
[b]组织布局文件
[/b]如果你不知道如何规范化一个布局XML文件,可参考下面惯例:
[list]
[*]每行一个属性,缩进4个空格;[/*]
[*]android:id永远放在第一个;[/*]
[*]android:layout_** 属性要放在顶部;[/*]
[*]style属性放在尾部;[/*]
[*]结束标志位 />要独占一行,有助于对属性排序或添加;[/*]
[*]不要写hard code,如 android:text,对于Android Studio来说可考虑使用Designtime attributes方法。[/*]
[/list]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<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>