[关闭]
@SmartDengg 2017-07-18T08:40:01.000000Z 字数 16208 阅读 1577

Android编码规范


使用Android studio作为集成开发环境

对于编辑器,每个人都有自己的选择,让编辑器根据工程结构和构建系统高效运作,是每个人的责任。

推荐使用Android Studio,由谷歌开发,并且最接近Gradle,默认使用最新的工程结构。相比较而言Eclipse ADT使用旧的工程结构和Ant作为构建系统,它不仅需要繁琐的配置,而且gardleadb命令行同样需要学习成本。

使用Gradle构建项目

默认编译环境使用Gradle。Ant不仅有限制而且操作方式非常繁琐,使用Gradle编译,可以轻松实现以下几点:

  1. 构建App的不同版本,在debug和release之间轻松切换。
  2. 快速制作简单的脚本任务
  3. 轻松下载和管理依赖库
  4. 能够方便的按照要求定制Keystore

另外值得一提的是,如果你想更快的构建小规模可重用程序模块,可以采用Facebook Buck,与传统Android编译工具相比,Buck凭借多核及并行技术,极大加速了Android工程的编译速度,并且在多次编译中,它会对未变动的模块进行标记,从而以增量式编译的方式进一步提高构建速度。

项目结构

废弃过时的Ant & Eclipse ADT工程结构,统一使用新的Gradle & Android Studio的工程结构。

要使用Android studio结构:

  1. new-link-structure
  2. ├─ library-imsdk
  3. ├─ app
  4. ├─ libs
  5. ├─ src
  6. ├─ androidTest
  7. └─ java
  8. └─ com/im/project
  9. └─ main
  10. ├─ java
  11. └─ com/im/project
  12. ├─ res
  13. └─ AndroidManifest.xml
  14. ├─ build.gradle
  15. └─ proguard-rules.pro
  16. ├─ build.gradle
  17. └─ settings.gradle

不使用Eclipse结构:

  1. old-link-structure
  2. ├─ assets
  3. ├─ libs
  4. ├─ res
  5. ├─ src
  6. └─ com/im/project
  7. ├─ AndroidManifest.xml
  8. ├─ build.gradle
  9. ├─ project.properties
  10. └─ proguard-rules.pro

通过比较可见Android studio的项目结构更加清晰,强调了Gradle概念。其中library-imsdkapp所依赖的module。

签名配置

发布release版本的时候,必须确认SigningConfigs的保密性:

创建一个不加入版本控制系统的gradle.properties文件,或者记录在本地的local.properties中。

  1. KEYSTORE_PASSWORD=storePassword
  2. KEY_PASSWORD=keyPassword

上面提到的两个文件会被gradle自动引入,因此可以在buld.gradle中直接引用,例如:

  1. signingConfigs {
  2. release {
  3. try {
  4. storeFile file("myapp.keystore")
  5. storePassword KEYSTORE_PASSWORD
  6. keyAlias "storeKey"
  7. keyPassword KEY_PASSWORD
  8. }
  9. catch (ex) {
  10. throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
  11. }
  12. }
  13. }

不采用以下示例方式,因为这会导致敏感信息的泄露:

  1. signingConfigs {
  2. release {
  3. storeFile file("myapp.keystore")
  4. storePassword "storePassword"
  5. keyAlias "storeKey"
  6. keyPassword "keyPassword"
  7. }
  8. }

使用Maven依赖代替jar包导入

如果在项目中明确使用jar文件,那么它们可能成为永久的版本,如2.1.1。而且很容易陷入频繁更新jar包的繁琐工作中,Maven很好的解决了这个问题,这也是 Gradle构建中推荐的使用方式,例如:

  1. dependencies {
  2. /*ReactiveX Library*/
  3. compile 'io.reactivex:rxjava:1.1.3'
  4. compile 'io.reactivex:rxandroid:1.1.0'
  5. }

或者,在不确定该library最新版本的前提下,可以指定版本范围,如2.1.+,随后Gradle会优先加载Maven仓库中该library的最新版本。

命名规范

Java文件

参考源码命名规则,对Java类文件使用驼峰命名法

对于继承自Android组件的类来说,类名应该以这个组件的类型作后缀,如:

SignInActivity, UserProfileFragment, ImageUploaderService, ChangePasswordDialog

XML文件

资源等.xml文件要采用小写字母_下划线的组合形式。

Drawable相关

Asset Type Prefix Example
Action bar ab_ ab_stacked.9.png
Button btn_ btn_send_pressed.9.png
Dialog dialog_ dialog_top.9.png
Divider divider_ divider_horizontal.9.png
Icon ic_ ic_star.png
Menu menu_ menu_submenu_bg.9.png
Notification notification_ notification_bg.9.png
Tabs tab_ tab_pressed.9.png
Asset Type Prefix Example
Icons ic_ ic_star.png
Launcher icons ic_launcher ic_launcher_calendar.png
Menu icons and Action Bar icons ic_menu ic_menu_archive.png
Status bar icons ic_stat_notify ic_stat_notify_msg.png
Tab icons ic_tab ic_tab_recent.png
Dialog icons ic_dialog ic_dialog_info.png
State Suffix Example
Normal _normal btn_order_normal.9.png
Pressed _pressed btn_order_pressed.9.png
Focused _focused btn_order_focused.9.png
Disabled _disabled btn_order_disabled.9.png
Selected _selected btn_order_selected.9.png

Layout相关

布局文件应该与Android组件的命名相匹配,以组件类型作为前缀,并且能够清晰的表达意图。例如:如果为SignInActivity创建一个布局文件,那么应该命名为activity_sign_in.xml。建议采用以下基本命名规则:

Component Class Name Layout Name
Activity UserProfileActivity activity_user_profile.xml
Fragment SignUpFragment fragment_sign_up.xml
Dialog ChangePasswordDialog dialog_change_password.xml
AdapterView item item_person.xml
Partial layout partial_stats_bar.xml

值得一提的是,一些布局文件需要通过Adapter填充,如ListViewRecyclerview等列表视图,这种场景下,布局的命名应该以item_作为前缀。另外还有一种比较常见的情况,一个布局文件作为另一个布局文件的一部分而存在,或者使用了includemerge等标签的布局,建议使用partial_include_或者merge_作为前缀,这一类布局的命名同样应该清晰的表达其意图。

控件Id的命名应该以该控件类型的缩写作为前缀,同样要使用小写字母_下划线的组合形式,能够清晰表达意图是命名的前提:

Element Prefix
TextView tv_
ImageView iv_
Button btn_
Menu menu_

示例如下:

  1. <ImageView
  2. android:id="@+id/iv_profile"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content" />
  1. <menu>
  2. <item
  3. android:id="@+id/menu_done"
  4. android:title="Done" />
  5. </menu>

Color相关

colors.xml可以比喻成“调色板”,只映射ARGB值,不应该存在其他类型的数值,更不要使用它为不同的按钮来定义ARGB。

应该根据颜色或者风格对ARGB赋值,要使用基色_ARGB的命名规则:

  1. <resources>
  2. <color name="white_FFFFFF">#FFFFFF</color>
  3. <color name="gray_DBDBDB">#DBDBDB</color>
  4. <color name="gray_939393">#939393</color>
  5. <color name="gray_5F5F5F">#5F5F5F</color>
  6. <color name="black_323232">#323232</color>
  7. <color name="green_27D34D">#27D34D</color>
  8. </resources>

值得一提的是,这样规范的颜色很容易修改或重构,App所使用的颜色数量和种类也会变得非常清晰。

相反地,不使用以下对色值的命名规则:

  1. <resources>
  2. <color name="button_foreground">#FFFFFF</color>
  3. <color name="button_background">#2A91BD</color>
  4. <color name="comment_background_inactive">#5F5F5F</color>
  5. <color name="comment_background_active">#939393</color>
  6. <color name="comment_foreground">#FFFFFF</color>
  7. <color name="comment_foreground_important">#FF9D2F</color>
  8. ...
  9. <color name="comment_shadow">#323232</color>

使用这种定义方式,我们需要非常的谨慎,一不小心就会重复定义ARGB,而且当改变基本色时,会造成毫无意义的重复操作。

Dimen相关

我们应该像对待colors.xml一样对待dimens.xml文件,与定义“调色板”无异,同样应该为字体定义一块“字号版”。

要使用以dimen_作为前缀的命名规范:

  1. <resources>
  2. <!--SP-->
  3. <dimen name="dimen_22sp">22sp</dimen>
  4. <dimen name="dimen_18sp">18sp</dimen>
  5. <dimen name="dimen_15sp">15sp</dimen>
  6. <!--DP-->
  7. <dimen name="dimen_60dp">60dp</dimen>
  8. <dimen name="dimen_40dp">40dp</dimen>
  9. <dimen name="dimen_32dp">32dp</dimen>
  10. </resources>

这样写的好处是,使组织结构和修改布局风格变得非常容易,同时也避免了对重复数值的定义。

String相关

string的声明必须添加业务区分标识,前缀应该能清楚地表达功能职责,如,registration_email_hintregistration_name_hint。如果一个Sting不属于任何模块,就意味着它是通用的,遵循以下规范:

Prefix Description
error_ 错误提示
msg_ 一般信息提示
title_ 标题提示,如,Dialog标题
action_ 动作提示,如,“保存”,“取消”,“创建”

Style与Theme相关

Style与Theme的命名统一使用驼峰命名法。请谨慎使用styletheme,避免重复冗余的文件出现。可以出现多个styles.xml 文件,如:styles.xmlstyle_home.xmlstyle_item_details.xmlstyles_forms.xml等。

另外值得一提的是:res/values目录下的文件可以任意命名,但前提是该文件能够明确表达职责所属,因为起作用的并不是文件本身,而是内部的标签属性。

编码规范与指导方针

XML文件规范

属性排序

对于如何排版一个布局文件,建议编码规范如下:

xml示例如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:orientation="vertical"
  7. >
  8. <TextView
  9. android:id="@+id/name"
  10. style="@style/FancyText"
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. android:layout_alignParentRight="true"
  14. android:text="@string/name"
  15. />
  16. <include layout="@layout/reusable_part" />
  17. </LinearLayout>

使用tools标签预览视图

要使用如下示例方式设置属性:

  1. <TextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. tools:text="Home Link" />

不要使用以下硬编码方式:

  1. <TextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:text="Home Link" />

通用style

参数校验

另外,在上面提到的准则中,有以下几点需要注意:

避免层级冗余的嵌套

Layout结构优化方面,应尽量避免深层次的布局嵌套,这不仅会引发性能瓶颈,还会带来项目维护上的麻烦。在书写布局之前应该对ViewTree充分的分析,善用<merge>标签减少层级嵌套,或者使用Hierarchy Viewer等UI优化工具对Layout进行分析与优化。可参考Optimizing Your UIOptimizing Layout Hierarchies

Java代码规范

代码注释

创建class文件时,文件头部必须添加作者的全称拼音,创建时间以及对本类的描述。创建方法函数时,被public声明的函数,必须添加注释,除getXXXX()setXXXX()等简单函数外,可不必在方法头中添加注释,但需要对所操作的字段添加描述,这里提供一个注释样板,可供参考:

  1. /**
  2. * 创建时间:2016/7/18 15:46 <br>
  3. * 作者: dengwei <br>
  4. * 描述: HTTP响应结果,状态码在[200..300)区间之外的异常信息包装类<br>
  5. */
  6. public final class HttpException extends Exception {
  7. //HTTP状态码
  8. private final int code;
  9. //HTTP状态行信息
  10. private final String message;
  11. //HTTP完成响应
  12. private final transient Response<?> response;
  13. public HttpException(Response<?> response) {
  14. super("HTTP " + response.code() + " " + response.message());
  15. this.code = response.code();
  16. this.message = response.message();
  17. this.response = response;
  18. }
  19. /**
  20. * 获取HTTP响应异常时的状态码,状态码的值在[200..300)区间外
  21. *
  22. * @return HTTP响应状态码
  23. */
  24. public int code() {
  25. return code;
  26. }
  27. /**
  28. * 获取HTTP响应异常时的状态行信息,如果状态信息未知,返回值可能等与null。
  29. *
  30. * @return HTTP响应状态行信息
  31. */
  32. public String message() {
  33. return message;
  34. }
  35. /**
  36. * 获取完整的HTTP响应,可以从这里获取更多的响应信息。如果该异常已经被序列化了,返回值可能等于null。
  37. * @return 完整的HTTP响应
  38. */
  39. public Response<?> response() {
  40. return response;
  41. }
  42. }

参数校验

绝大多数方法和构造器对于传递给它们的参数值都会有某些限制。例如,索引值必须是非负数,对象引用不能为null,等等这些都是很常见的。我们应该尽可能的在文档中清晰指明所有这些限制,并且在方法体的开头处检查参数,以强制施加这些限制。这是“应该在发生错误之后尽快检测出错误”这一普遍原则的一个具体情形。如果不能做到这一点,检测错误的可能性就比较小,即使检测到错误了,也比较难以确定错误的根源。

如:

构造函数和方法函数的有效性校验:

  1. public class Foo {
  2. private int age;
  3. private String name;
  4. public Foo(int age) {
  5. if (age < 0) throw new IllegalArgumentException("age < 0: " + age);
  6. this.age = age;
  7. }
  8. public void setName(String name) {
  9. if (name == null) throw new IllegalArgumentException("name = null");
  10. this.name = name;
  11. }
  12. }

Builder构造器有效性校验:

  1. public class Foo {
  2. private int age;
  3. private String name;
  4. private Foo(int age, String name) {
  5. this.age = age;
  6. this.name = name;
  7. }
  8. public static class Builder {
  9. private int age;
  10. private String name;
  11. public Builder age(int age) {
  12. if (age < 0) throw new IllegalArgumentException("age < 0: " + age);
  13. this.age = age;
  14. return this;
  15. }
  16. public Builder setName(String name) {
  17. if (name == null) throw new IllegalArgumentException("name = null");
  18. this.name = name;
  19. return this;
  20. }
  21. public Foo build() {
  22. return new Foo(age, name);
  23. }
  24. }
  25. }

在有些情况下,有效性检查工作非常的昂贵,或者根本是不切实际的,而且有效性检查已经隐含在计算过程中完成。例如,考虑对一个列表进行排序的方法:Collections.sort(List)要求列表中的所有对象都必须是可以相互比较的。在为列表排序的过程中,列表中的每个对象将与其他某个对象进行比较。如果这些对象不能相互比较,就会抛出ClassCastException,这正是sort()方法所应该做的。因此提前对列表中的所有元素进行有效性校验,显然没有多大意义。

另外值得一提的是,某些计算会隐式的执行必要的有效性校验,但是如果检查不成功就会抛出错误异常。换句话说,由于无效的参数值而导致计算过程抛出的异常,与文档中标明这个方法将抛出的异常并不相符。在这种情况下,就应该使用异常转译技巧,将计算过程中抛出的异常转换为正确的异常。我们拿上面的sort()方法的包装函数做举例说明:

  1. public static class Utils {
  2. public static void sortByAge(List<Foo> fooList) {
  3. try {
  4. Collections.sort(fooList);
  5. } catch (ClassCastException e) {
  6. throw new IllegalArgumentException("element in fooList must implements \"Comparable\"!");
  7. }
  8. }
  9. }

在设计方法的时候,不要认为对参数的任何限制都是件好事。相反,我们应该使它们尽可能的通用,并符合实际需要。假如方法对于它能接受的所有参数值都正常的完成工作,这时对参数的限制就应该越少越好。然后,通常情况下,有些限制对于
被实现的抽象来说是固有的。

总结,每当编写方法或者构造器的时候,就应该考虑它的参数有哪些限制。应该把这些限制尽可能的写进文档里,并在方法的开头处,通过显式的检查来实施这些有效性的校验,只要有一次校验失败,那些你为参数有效性校验所付出的努力,就得到了丰厚的回报。

处理Exception

如果对异常没有任何处理方案,至少应该在catch代码块中添加打印异常逻辑e.printStackTrace(),不建议采用的处理方式:

  1. void setServerPort(String value) {
  2. try {
  3. serverPort = Integer.parseInt(value);
  4. } catch (NumberFormatException e) { }
  5. }

你可能认为这种异常的触发概率极低,或者认为即便发生,也不需要做着重的处理,因此在catch()代码块中不添加任何逻辑,这大大增加了定位异常的难度,这里的建议是尽量处理每一个异常,具体的处理逻辑依赖于所处的上下文场景,对异常的处理同样能够增加系统的弹性,让程序变更健壮。

同时,遇到异常应该列出所有最小集合,不建议使用类似genericHandler()的通用异常捕获逻辑:

  1. try {
  2. potentialIOExceptionFun(); // may throw IOException
  3. potentialParsingExceptionFun(); // may throw ParsingException
  4. potentialSecurityExceptionFun(); // may throw SecurityException
  5. // phew, made it all the way
  6. } catch (Exception e) { // I'll just catch all exceptions
  7. genericHandler(); // with one generic handler!
  8. }

应该在catch语句中对异常分别处理,或者调用日志上传、异常统计等API。

Field定义与命名规范

对Field的定义应该放在文件的首位,并且遵守以下规范:

示例:

  1. public class MyClass {
  2. public static final int SOME_CONSTANT = 42;
  3. public int publicField;
  4. private static MyClass sSingleton;
  5. int mPackagePrivate;
  6. private int mPrivate;
  7. protected int mProtected;
  8. }

名词缩写规范

Good Bad
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
String url String URL
long id long ID

注解使用规范

  1. //泛型擦除
  2. @SuppressWarnings("unchecked")
  3. public static <R> FeedbackUseCase<R> createdUseCase() {
  4. return (FeedbackUseCase<R>) new FeedbackUseCase();
  5. }
  6. //请先确保能够非常正确地使用Handler
  7. @SuppressWarnings("handlerLeak")
  8. private Handler mHandler = new Handler() {
  9. @Override
  10. public void handleMessage(Message msg) {
  11. super.handleMessage(msg);
  12. }
  13. };

更多关于注解的使用技巧与规范请参考这里,或者使用android.support.annotation依赖包中的注解优化程序。

限制变量的作用域

定义变量时,应该保证变量所在域的最小化,这样做不仅能够增加代码的可读性和可维护性,还能有效减少出错的可能性。变量定义在尽可能小的域中,也是良好封装性的体现。

值得注意的是,变量应该在首次使用时被初始化,如果没有足够的条件来使用它,那么就应该延迟创建的时机,直到真正需要使用时再去进行初始化操作。

Log输出规范

使用Log类打印一些重要的信息对开发者而言是很重要的事情,切记不要使用Toast来做信息打印。

针对不同的信息使用对应的日志输出类型:

一般情况下,当前类名作为tag,并且使用static final修饰,当前类的首行,示例如下:

  1. public class MyClass {
  2. private static final String TAG = MyClass.class.getSimpleName();
  3. public myMethod() {
  4. Log.e(TAG, "My error message");
  5. }
  6. }

VERBOSEDEBUG类型的Log不应该出现在Release版本中,INFORMATIONWARNINGERROR类型的Log可以留下来,因为这些信息的输出能够帮助我们快速地定位问题所在,当然前提是,需要隐藏重要的信息输出,如,用户手机号,邮箱等。

只在Debug环境中输出日志的小技巧:

  1. if (BuildConfig.DEBUG) Log.d(TAG, "The value of x is " + x);

类成员排序规范

关于这个并没有硬性要求,不过好的排序方式,能够提高可读性和易学性。这里给出一些排序建议:

  1. 常量
  2. 字段
  3. 构造函数
  4. 被重写的函数(不区分修饰符类型)
  5. private修饰的函数
  6. public修饰的函数
  7. 被定义的内部类或者接口

示例如下:

  1. public class MainActivity extends Activity {
  2. private static final String TAG = MainActivity.class.getSimpleName();
  3. private String mTitle;
  4. private TextView mTextViewTitle;
  5. @Override
  6. public void onCreate() {
  7. ...
  8. }
  9. private void setUpView() {
  10. ...
  11. }
  12. public void setTitle(String title) {
  13. mTitle = title;
  14. }
  15. static class AnInnerClass {
  16. }
  17. }

如果继承了Android组件,比如Activity或者Fragment,重写生命周期函数时,建议按照组件的生命周期进行排序,如:

  1. public class MainActivity extends Activity {
  2. @Override
  3. public void onCreate() {}
  4. @Override
  5. public void onResume() {}
  6. @Override
  7. public void onPause() {}
  8. @Override
  9. public void onDestroy() {}
  10. }

方法函数中的参数排序规范

在Android日常开发中,很多情况下都需要使用Context,所以经常被作为参数传入方法中,这里给出的建议是,如果函数签名中存在Context,则作为第一个参数,如果存在Callback则作为最后一个参数,示例如下:

  1. public void loadUserAsync(Context context, int userId, UserCallback callback);

字符串常量的命名与赋值规范

Android SDK中诸如SharedPreferencesBundleIntent等,都采用key-value的方式进行赋值,当使用这些组件时,key必须被static final所修饰,并且命名应该符合以下规范:

Element Field Name Prefix
SharedPreferences PREF_
Bundle BUNDLE_
Fragment Arguments ARGUMENT_
Intent Extra EXTRA_
Intent Action ACTION_

需要注意的是,当调用Fragment的.getArguments()方法时,返回值同样是一个Bundle,因为这也是一个常用函数,因此我们需要定义一个不同的前缀,示例如下:

  1. static final String PREF_EMAIL = "PREF_EMAIL";
  2. static final String BUNDLE_AGE = "BUNDLE_AGE";
  3. static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
  4. static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
  5. static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";

Activity和Fragment打开方式

当通过Intent或者BundleActivityFragment传值时,应该遵循上面提到的key-value规范,公开一个被public static修饰的方法,方法的参数应该包含所有打开这个Activity或者Fragment的信息,示例如下:

  1. public static void startActivity(AppCompatActivity startingActivity, User user) {
  2. Intent intent = new Intent(startingActivity, ThisActivity.class);
  3. intent.putParcelableExtra(EXTRA_USER, user);
  4. startingActivity.startActivity(intent);
  5. }
  1. public static UserFragment newInstance(User user) {
  2. UserFragment fragment = new UserFragment;
  3. Bundle args = new Bundle();
  4. args.putParcelable(ARGUMENT_USER, user);
  5. fragment.setArguments(args)
  6. return fragment;
  7. }

需要注意一下两点:

  1. 以上这些方法应该放在类的开头,至少应该放在.onCreate()之前。
  2. Intent中所涉及的key,如EXTRA_USERARGUMENT_USER等,如果与其他业务无关,应该放在本类中被private所修饰,不暴露给其它外部类。如果是通用key,则应该声明在公共Common文件中。

提高程序可读性

我们应该在日常开发中养成添加注释的习惯,避免魔鬼数字硬编码的出现,这样不仅可以提高可读性与可维护性,还能为逻辑的重构带来很大的便捷。

这里有个很好的建议,使用RxJava让程序变得更加可读,更加函数化。

这里有一个示例,可供参考,“对一个数组中的每一个元素乘以2,然后筛选小于10的元素,并放入最终的集合中”

一般写法示例:

  1. Integer[] integers = { 0, 1, 2, 3, 4, 5 };
  2. Integer[] doubles = new Integer[integers.length];
  3. for (int i = 0; i < integers.length; i++) {
  4. doubles[i] = integers[i] * 2;
  5. }
  6. List<Integer> results = new ArrayList<>(doubles.length);
  7. for (Integer integer : doubles) {
  8. if (integer < 10) {
  9. results.add(integer);
  10. }
  11. }

使用RxJava的流式调用示例,提高可读性:

  1. //假设你了解这些操作符的工作原理
  2. List<Integer> results = Observable.from(integers)
  3. .map(new Func1<Integer, Integer>() {
  4. @Override
  5. public Integer call(Integer integer) {
  6. return integer * 2;
  7. }
  8. })
  9. .filter(new Func1<Integer, Boolean>() {
  10. @Override
  11. public Boolean call(Integer integer) {
  12. return integer < 10;
  13. }
  14. })
  15. .toList()
  16. .toBlocking()
  17. .first();

另外需要补充的一点是:当使用Builder或者其他链式结构创建对象时,每一个方法的调用都应另起一行,并且每一行都以.开头,示例如下:

  1. Picasso.with(context)
  2. .load(R.drawable.placeholder)
  3. .into(imageView);

Git分支管理与提交规范

多人协作开发情况下,每个人都应该了解并理解Git分支模型

这里意见几篇质量极高的文章以供参阅,因此不再赘述。

git版本控制开发流程小结笔记(一)

git版本控制开发流程小结笔记(二)

一个成功的 Git 分支模型

因为Git的操作指令非常灵活,所以这里只给出提交备注的建议:

1. 提交备注

下面是几个常用提交动词,以供参考:

2. 标题尽量不超过50个字符

3. 标题的首字母大写(如果你习惯使用一个英文标题的话)

使用这种标题:

    Accelerate to 88 miles per hour

而不是:

    accelerate to 88 miles per hour

4. 标题不以“句号”作为结尾

使用这种标题:

    Open the pod bay doors

而不是:

    Open the pod bay doors.

5. 内容描述尽量不要超过72个字符

6. 在内容中对此次提交的“Why”以及“How”来进行描述

最后,我们一起来看一看,一个优雅的提交备注是什么样子的:

   Simplify serialize.h's exception handling

   Remove the 'state' and 'exceptmask' from serialize.h's stream
   implementations, as well as related methods.

   As exceptmask always included 'failbit', and setstate was always
   called with bits = failbit, all it did was immediately raise an
   exception. Get rid of those variables, and replace the setstate
   with direct exception throwing (which also removes some dead
   code).

   As a result, good() is never reached after a failure (there are
   only 2 calls, one of which is in tests), and can just be replaced
   by !eof().

   fail(), clear(n) and exceptions() are just never called. Delete
   them.
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注