#车厘子移动小组 - Android 编码规范
material-design 英文原版
material-design 中文版
参考资料
1)、https://github.com/ribot/android-guidelines
首推使用Android Studio,因为他是由谷歌开发,最接近Gradle,默认使用最新的工程结构,已经到release阶段(目前已经有release 2.2了),它就是为Android开发定制的。
并使用Square's Java and Android projects code style settings
作为code style
。
常用结构 参考Google's guide on Gradle for Android
小任务 除了(shell, Python, Perl, etc)这些脚本语言,你也可以使用Gradle 制作任务。 更多信息请参考Gradle's documentation。
密码 在做版本release时你app的 build.gradle
你需要定义 signingConfigs
.此时你应该避免以下内容:
不要做这个 . 这会出现在版本控制中。
signingConfigs {
release {
storeFile file("myapp.keystore")
storePassword "password123"
keyAlias "thekey"
keyPassword "password789"
}
}
而是,建立一个不加入版本控制系统的gradle.properties
文件。
KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789
那个文件是gradle自动引入的,你可以在buld.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构建中也是推荐的方法。你可
以指定版本的一个范围,如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.+'
}
规则:使用驼峰命名,前缀+逻辑名称,类变量名和布局文件id名称保持一致,不需要下划线分割
控件 | 缩写前缀 |
---|---|
TextView/EditText | text |
ImageView | img |
Button/RadioButton/ImageButton | btn |
RelativeLayout/LinearLayout/FrameLayout | layout |
ListView | listView |
WebView | webView |
CheckBox | checkBox |
ProgressBar | progressBar |
seekBar | seekBar |
其他控件 | 控件名首字母缩写作为前缀 |
- 如:TextView @+id/textTitle
- 如:EditView @+id/textName
- 如:Button @+id/btnSearch
规则: 使用前缀_逻辑名称命名,单词全部小写,单词间以 下划线 分割。
布局类型 | 布局前缀 |
---|---|
Activity | activity_ |
Fragment | fragment_ |
Include | include_ |
Dialog | dialog_ |
PopupWindow | popup_ |
Menu | menu_ |
Adapter | recycler_item_ |
规则: 使用 前缀_用途 命名,单词全部小写,单词间以 下划线 分割。
- 图片资源文件命名
前缀 | 说明 |
---|---|
bg_xxx | 各类背景图片 |
btn_xxx | 这种按钮没有其他状态 |
ic_xxx | 图标,一般用于单个图标 |
bg_描述_状态1[_状态2] |
用于控件上的不同状态 |
btn_描述_状态1[_状态2] |
用于按钮上的不同状态 |
chx_描述_状态1[_状态2] |
选择框,一般有2态和4态 |
- 第三方资源文件,不管在value、drawable
必须携带第三方资源前缀 |
---|
umeng_socialize_style.xml |
pull_refresh_attrs.xml |
规则: 使用驼峰规则,首字母必须大写,使用名词或名词词组。要求简单易懂,富于描述,不允许出现无意义或错误单词。
类 | 描述 | 例如 |
---|---|---|
Application类 | Application为后缀标识 | XXXApplication |
Activity类 | Activity为后缀标识 | 闪屏页面类SplashActivity |
解析类 | Handler为后缀标识 | |
公共方法类 | Utils或Manager为后缀标识 | |
线程池管理类 | ThreadPoolManager | |
日志工具类 | LogUtils | |
数据库类 | 以DBHelper后缀标识 | MySQLiteDBHelper |
Service类 | 以Service为后缀标识 | 播放服务:PlayService |
BroadcastReceiver类 | 以Broadcast为后缀标识 | 时间通知:TimeBroadcast |
ContentProvider类 | 以Provider为后缀标识 | 单词内容提供者:DictProvider |
直接写的共享基础类 | 以Base为前缀 | BaseActivity,BaseFragment |
规则: 使用驼峰规则,首字母必须小写,使用动词。要求简单易懂,富于描述,不允许出现无意义或错误单词。
方法 | 说明 |
---|---|
initXX() | 初始化相关方法,使用init为前缀标识,如初始化布局initView() |
httpXX() | http业务请求方法,以http为前缀标识 |
getXX() | 返回某个值的方法,使用get为前缀标识 |
saveXX() | 与保存数据相关的,使用save为前缀标识 |
deleteXX() | 删除操作 |
resetXX() | 对数据重组的,使用reset前缀标识 |
clearXX() | 清除数据相关的 |
isXX() | 方法返回值为boolean型的请使用is或check为前缀标识 |
processXX() | 对数据进行处理的方法,尽量使用process为前缀标识 |
displayXX() | 弹出提示框和提示信息,使用display为前缀标识 |
drawXXX() | 绘制数据或效果相关的,使用draw前缀标识 |
规则: 使用驼峰规则,首字母必须小写,使用名词或名词词组。要求简单易懂,富于描述,不允许出现无意义或错误单词。
- 成员变量命名,自定义变量前添加m前缀,布局控件变量不用添加m前缀
- 常量命名,全部大写,单词间用下划线隔开
- 命名 遵循前缀表明类型的习惯,形如
type_foo_bar.xml
。例如:fragment_contact_details.xml
,view_primary_button.xml
,activity_main.xml
.
组织布局文件 若果你不确定如何排版一个布局文件,遵循一下规则可能会有帮助。
- 考虑使用Designtime attributes 设计时布局属性,Android Studio已经提供支持,而不是硬编码
android:text
(译者注:墙内也可以参考stormzhang的这篇博客链接)。
作为一个经验法则,android:layout_****
属性应该在 layout XML 中定义,同时其它属性android:****
应放在 style XML中。此规则也有例外,不过大体工作的很好。这个思想整体是保持layout属性(positioning, margin, sizing) 和content属性在布局文件中,同时将所有的外观细节属性(colors, padding, font)放在style文件中。
例外有以下这些:
android:id
明显应该在layout文件中- layout文件中
android:orientation
对于一个LinearLayout
布局通常更有意义 android:text
由于是定义内容,应该放在layout文件中- 有时候将
android:layout_width
和android:layout_height
属性放到一个style中作为一个通用的风格中更有意义,但是默认情况下这些应该放到layout文件中。
使用styles 几乎每个项目都需要适当的使用style文件,因为对于一个视图来说有一个重复的外观是很常见的。 在应用中对于大多数文本内容,最起码你应该有一个通用的style文件,例如:
<style name="ContentText">
<item name="android:textSize">@dimen/font_normal</item>
<item name="android:textColor">@color/basic_black</item>
</style>
应用到TextView 中:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/price"
style="@style/ContentText"
/>
你或许需要为按钮控件做同样的事情,不要停止在那里。将一组相关的和重复android:****
的属性放到一个通用的style中。
将一个大的style文件分割成多个文件 你可以有多个styles.xml
文件。Android SDK支持其它文件,styles
这个文件名称并没有作用,起作用的是在文件
里xml的<style>
标签。因此你可以有多个style文件styles.xml
,style_home.xml
,style_item_details.xml
,styles_forms.xml
。
不用于资源文件路径需要为系统构建起的有意义,在res/values
目录下的文件可以任意命名。
colors.xml
是一个调色板 在你的colors.xml
文件中应该只是映射颜色的名称一个RGBA值,而没有其它的。不要使用它为不同的按钮来定义RGBA值。
不要这样做
<resources>
<color name="button_foreground">#FFFFFF</color>
<color name="button_background">#2A91BD</color>
<color name="comment_background_inactive">#5F5F5F</color>
<color name="comment_background_active">#939393</color>
<color name="comment_foreground">#FFFFFF</color>
<color name="comment_foreground_important">#FF9D2F</color>
...
<color name="comment_shadow">#323232</color>
使用这种格式,你会非常容易的开始重复定义RGBA值,这使如果需要改变基本色变的很复杂。同时,这些定义是跟一些环境关联起来的,如button
或者comment
,
应该放到一个按钮风格中,而不是在color.xml
文件中。
相反,这样做:
<resources>
<!-- grayscale -->
<color name="white" >#FFFFFF</color>
<color name="black" >#323232</color>
<color name="Gray">#888888</color>
<color name="Gray100">#dddddd</color>
<color name="Gray600">#999999</color>
<!-- basic colors -->
<color name="green">#27D34D</color>
<color name="blue">#2A91BD</color>
<color name="orange">#FF9D2F</color>
<color name="red">#FF432F</color>
</resources>
向应用设计者那里要这个调色板,名称不需要跟"green", "blue", 等等相同。 "brand_primary", "brand_secondary", "brand_negative" 这样的名字也是完全可以接受的。 像这样规范的颜色很容易修改或重构,会使应用一共使用了多少种不同的颜色变得非常清晰。 通常一个具有审美价值的UI来说,减少使用颜色的种类是非常重要的。
像对待colors.xml一样对待dimens.xml文件 与定义颜色调色板一样,你同时也应该定义一个空隙间隔和字体大小的“调色板”。 一个好的例子,如下所示:
<resources>
<!-- font sizes -->
<dimen name="font_larger">22sp</dimen>
<dimen name="font_large">18sp</dimen>
<dimen name="font_normal">15sp</dimen>
<dimen name="font_small">12sp</dimen>
<!-- typical spacing between two views -->
<dimen name="spacing_huge">40dp</dimen>
<dimen name="spacing_large">24dp</dimen>
<dimen name="spacing_normal">14dp</dimen>
<dimen name="spacing_small">10dp</dimen>
<dimen name="spacing_tiny">4dp</dimen>
<!-- typical sizes of views -->
<dimen name="button_height_tall">60dp</dimen>
<dimen name="button_height_normal">40dp</dimen>
<dimen name="button_height_short">32dp</dimen>
</resources>
布局时在写 margins 和 paddings 时,你应该使用spacing_****
尺寸格式来布局,而不是像对待String字符串一样直接写值。
这样写会非常有感觉,会使组织和改变风格或布局是非常容易。
避免深层次的视图结构 有时候为了摆放一个视图,你可能尝试添加另一个LinearLayout。你可能使用这种方法解决:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<RelativeLayout
...
>
<LinearLayout
...
>
<LinearLayout
...
>
<LinearLayout
...
>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
即使你没有非常明确的在一个layout布局文件中这样使用,如果你在Java文件中从一个view inflate 到其他views当中,也是可能会发生的。
可能会导致一系列的问题。你可能会遇到性能问题,因为处理起需要处理一个复杂的UI树结构。 还可能会导致以下更严重的问题StackOverflowError.
因此尽量保持你的视图tree:学习如何使用RelativeLayout,
如何 optimize 你的布局 和如何使用
<merge>
标签.
小心关于WebViews的问题. 如果你必须显示一个web视图, 比如说对于一个新闻文章,避免做客户端处理HTML的工作, 最好让后端工程师协助,让他返回一个 "纯" HTML。 WebViews 也能导致内存泄露 当保持引他们的Activity,而不是被绑定到ApplicationContext中的时候。 当使用简单的文字或按钮时,避免使用WebView,这时使用TextView或Buttons更好。
style="@style/TextAppearance.AppCompat.Display4"
style="@style/TextAppearance.AppCompat.Display3"
style="@style/TextAppearance.AppCompat.Display2"
style="@style/TextAppearance.AppCompat.Display1"
style="@style/TextAppearance.AppCompat.Headline"
style="@style/TextAppearance.AppCompat.Title"
style="@style/TextAppearance.AppCompat.Subhead"
style="@style/TextAppearance.AppCompat.Body2"
style="@style/TextAppearance.AppCompat.Body1"
style="@style/TextAppearance.AppCompat.Caption"
style="@style/TextAppearance.AppCompat.Button"
如果项目比较小的话:
- app——Application Activity Fragment Presenter等的顶级父类
- config——API,常量表等
- model——数据层
- entities——数据模型
- presenter——MVP的P
- view——MVP的V
- utils——工具类集合
- widget——各个可复用View集合
如果项目比较大,上面的方式一定会造成presenter和view里近百个文件。 推荐下列方式:
- app
- config
- model
- entities
- module——将界面层以功能模块分配包。
- launch
- main
- account
- news
- music
- ……
- utils
- widget
#6、配置主题
##6.1 先在color.xml中写好需要的颜色:
<resources>
<color name="Orange">#ff5722</color>
<color name="DeepPurple">#673AB7</color>
<color name="DeepPurple900">#311B92</color>
<color name="White">#fff</color>
<color name="Gray">#888888</color>
<color name="Gray100">#dddddd</color>
<color name="Gray600">#999999</color>
</resources>
注意color.xml是配色表。应该是描述颜色而不是对字体颜色,背景颜色等的定义。这样能防止相近的颜色重复定义,而导致界面颜色不统一。
##6.2 在style.xml里定义主题:
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/DeepPurple</item>
<item name="colorPrimaryDark">@color/DeepPurple900</item>
<item name="colorAccent">@color/Orange</item>
</style>
<style name="AppTheme" parent="AppTheme.Base"></style>
在res目录下,创建一个values-v21目录,再创建一个style.xml:
<style name="AppTheme" parent="AppTheme.Base">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">?colorPrimaryDark</item>
</style>
然后在AndroidManifest.xml文件中修改application的theme属性为上面定义的AppTheme,即可实现沉浸式状态栏。
- Activity继承BaseFragmentActivity或SwipeBackActivity,可以使用ButterKnife注解代替findViewById
- 方法
- 拆分臃肿方法,每个方法只作一件事
- 做同一个逻辑的方法,尽量靠近放到一块,方便查看
- 不要使用 try catch 处理业务逻辑
- 使用JSON工具类,不要手动解析和拼装数据
- 控制语句
- 减少条件嵌套,不要超过3层
- if判断使用“卫语句”,减少层级
if(obj != null) { doSomething(); }
修改为:if(obj == null) { return; } doSomething();
- if语句必须用{}包括起来,即便是只有一句
- 处理“魔数”等看不懂的神秘数字
- 代码中不要出现数字,特别是一些标识不同类型的数字。
- 所有意义数字全部抽取到Constant公共类中,避免散布在各位类中。
- 空行:空行将逻辑相关代码段隔开,简洁清楚,提高可读性
- 成员变量之间,根据业务形成分组加空行
- 方法之间加空行
- 用好TODO标记
- 记录想法,记录功能点,开发过程中可以利用TODO记录一下临时想法或为了不打扰思路留下待完善的说明
- 删除无用TODO,开发工具自动生成的TODO,或则已经完善的TODO,一定要删除。
##8、写在最后
- 什么是架构 软件架构绝对不只是框架的堆砌,架构是为了方便软件可维护、可扩展、安全性、易理解。
##9、附录A 软件设计六大原则:
- 单一职责原则 - Single Responsibility Principle
应该有且仅有一个原因引起类的变更。(如果类需要变更,那么只可能仅由某一个原因引起)
- 里氏替换原则 - Liskov Substitution Principle
所有引用基类的地方,都能透明地替换成其子类对象。只要父类能出现的地方,子类就可以出现。
- 依赖倒置原则 - Dependence Inversion Principle:
即“面向接口编程”: 高层模块不应该依赖低层模块,两者都应该依赖其抽象;——模块间的依赖通过抽象发生。实现类之间不发生直接的依赖关系(eg. 类B被用作类A的方法中的参数),其依赖关系是通过接口或抽象类产生的; 抽象不应该依赖细节;——接口或抽象类不依赖于实现类; 细节应该依赖抽象;——实现类依赖接口或抽象类。
- 接口隔离原则 - Interface Segregation Principle
客户端只依赖于它所需要的接口;它需要什么接口就提供什么接口,把不需要的接口剔除掉。 ——类间的依赖关系应建立在最小的接口上。 即,接口尽量细化,接口中的方法尽量少。
- 迪米特法则 - Law of Demeter
又称最少知识原则(Least Knowledge Principle),一个对象应该对其他对象有最少的了解。 一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
- 开闭原则 -Open Closed Principle
对扩展开放,对修改关闭。一个软件实体应该通过扩展来实现变化,而不是通过修改已有代码来实现变化。 一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。——but,并不意味着不做任何修改;底层模块的扩展,必然要有高层模块进行耦合。 “变化”可分为三种类型: 逻辑变化——不涉及其他模块,可修改原有类中的方法; 子模块变化——会对其他模块产生影响,通过扩展来完成变化; 可见视图变化——界面变化,有时需要通过扩展来完成变化。