Android编码规范指导

原文链接:https://github.com/bufferapp/android-guidelines/blob/master/project_style_guidelines.md 英语溜的可去看看,此文章是跟公司的小伙伴一起翻译的

为了保持我们的代码的基本整洁和一致,在安卓工程从始至终我们都应该遵循一定的规范,这篇文档的目的就是为了定义这样一个工程指导的规范。
虽然很多事情可以通过Jenkins的代码质量检查来加强,但重要的是要注意那些没有被检查到的地方。

1. 工程指导

1.1 工程结构

当进行提交代码的工作时,工程应该保持如下的目录结构:

src/androidTest
src/test
src/commonTest
src/main

androidTest - 功能测试目录
test - 单元测试目录
commonTest - 为AndroidTest & Test 提供的共享测试代码的目录
main - 应用代码目录

当你修改或者增加新功能的时候,工程结构依然应该保持如上的样子。
使用如上的工程结构可以让我们的应用代码从相关的测试代码中分离出来。
CommonTest目录使得我们的功能测试和单元测试可以共享部分代码,比如mock model creation and dagger test configuration classes.

1.2 文件命名

1.2.1 类文件

任何定义的类都应该使用驼峰命名格式,比如:

AndroidActivity, NetworkHelper, UserFragment, PerActivity

任何继承自android框架组建的类都应该使用组建名称来结尾,比如:

UserFragment, SignUpActivity, RateAppDialog, PushNotificationServer, NumberView

使用驼峰格式命名易于阅读。
用android框架组件名称结尾的继承类能够清楚的标识出类的用途
比如,如果要去查找修改RegistrationDialog时,那么这个命名使得定位这个类文件非常方便。

1.2.1 资源文件

当命名资源文件时,应该只使用小写字母和下划线替代空格,例如:

activity_main, fragment_user, item_post

在你查找布局文件时,这样命名同样使得定位文件很方便。
在使用android studio中,布局的包中的文件是按字母顺序排列的,这样意味着activity,fragment和其他的layout是按组分类放置的----所以你知道从哪里去开始找一个文件了。
不止如此,用组建名称开头的布局文件可以很清晰的标识这个布局文件是被那类组建使用。

1.2.2.1 Drawable 文件

Drawable resource files should be named using the ic_ prefix along with the size and color of the asset.
Drawable资源文件应该使用“ic_”前缀后跟上尺寸以及资源的颜色信息
For example, white accept icon sized at 24dp would be named:
比如,白色的24dp大小的用于接受动作的图标应该命名如下:

ic_accept_24dp_white

黑色用于取消动作的48dp大小的图标命名:

ic_cancel_48dp_black

我们使用这样的命名约定方便使用命名来组织drawable资源文件
如果命名中没有颜色和尺寸信息,那么开发者还需要打开drawable文件去查看这些信息。所以这样可以节约我们一点时间.
其他的drawable文件应该使用对应的前缀,如下:

Type
Prefix
Example
Selector selector_ selector_button_cancel
Background bg_ bg_rounded_button
Circle circle_ circle_white
Progress progress_ progress_circle_purple
Divider divider_ divider_grey

在Android Studio中这个命名约定依然可以帮助我们将相似的项组织到一起
并清晰的标识出这一文件用作什么
比如, 命令一个资源为“button_cancel”不能标识任何信息
这是一个selector资源呢还是一个圆角按钮背景呢?
正确的命名可以去除所有的引起的模棱两可.

在创建selector不同状态资源时,也应该使用对应的命名下标:

State
Suffix
Example
Normal _normal btn_accept_normal
Pressed _pressed btn_accept_pressed
Focused _focused btn_accept_focused
Disabled _disabled btn_accept_disabled
Selected _selected btn_accept_selected

使用如上清晰的下标绝对明显的标识出了selector状态资源的作用。
为有颜色和其他标识的资源文件增加下标,使得开发者在打开selector文件时就可以知道不同的selector资源的状态是什么了

1.2.2.2 Layout 文件

在命名布局文件时,应该用android组建的名称作为文件名的前缀,比如:

Component
Class Name
Layout Name
Activity MainActivity activity_main
Fragment MainFragment fragment_main
Dialog RateDialog dialog_rate
Widget UserProfileView view_user_profile
AdapterView Item N/A item_follower

注意:如果要创建的布局文件是有多个不同组件使用的,那么应该使用”layout_”前缀
这样不仅在层级目录中可以很方便的找到文件,
这样也可以帮助我们定义相应的这个layout布局文件归属的类。

1.2.2.3 Menu Files

菜单文件不需要使用“menu_”前缀。
在资源目录下已经有菜单包了,所以这是不必要的。

1.2.2.4 Values Files

所有的资源文件名必须是复数的,比如:

attrs.xml, strings.xml, styles.xml, colors.xml, dimens.xml


2. 代码指导

2.1 Java语句规则

2.1.1 绝不要忽略exceptions

正确的方式是避免没有处理的异常,如下:

public void setUserId(String id) {
    try {
        mUserId = Integer.parseInt(id);
    } catch (NumberFormatException e) { }
}

如果这里出现问题,这里不会打印出任何信息,而且也很难debug,只能让人迷惑。
当catch一个异常时,我们总是需要输出error日志到控制台,用于调试,如果必要的话,需要警告用户这个异常。比如:

<!-- lang:java-->
public void setCount(String count) {
    try {
        count = Integer.parseInt(id);
    } catch (NumberFormatException e) {
        count = 0;
        Log.e(TAG, "There was an error parsing the count " + e);
        DialogFactory.showErrorMessage(R.string.error_message_parsing_count);
    }
}

这里我们有如下的方式处理出错:
1. 显示一个信息给用户,提示他们这里出错了
2. 设置了一个可能的默认值
3. 抛出了一个合适的异常

2.1.2 绝对不要catch一般的异常:

public void openCustomTab(Context context, Uri uri) {
    Intent intent = buildIntent(context, uri);
    try {
        context.startActivity(intent);
    } catch (Exception e) {
        Log.e(TAG, "There was an error opening the custom tab " + e);
    }
}

为什么不要这样做呢?
在大部分情况下,catch这个通用的Exception或者Throwable都是不合适的。(特别是THrowable因为它包含Error的异常。)
这样意味着你没有期望到的异常(包括RuntimeExceptions像CLassCastException)都被抓获并在应用层进行error处理,这样是很危险的。
如果有人在你调用的代码里添加了一个新的类型的异常,编译器不会帮你认识到你需要处理这个不同的错误类型。这是你代码里很难发现的错误处理方式。
大多数情况下,你不应该用相同的处理方式来处理不同的exception.
如下,catch期望的异常并合适的处理:

public void openCustomTab(Context context, Uri uri) {
    Intent intent = buildIntent(context, uri);
    try {
        context.startActivity(intent);
    } catch (ActivityNotFoundException e) {
        Log.e(TAG, "There was an error opening the custom tab " + e);
    }
}

2.1.3 组织 exceptions

在异常运行相同的代码的地方,他们应该增加可读性和避免代码复制。比如,你可能会像如下这样处理异常:

public void openCustomTab(Context context, @Nullable Uri uri) {
    Intent intent = buildIntent(context, uri);
    try {
        context.startActivity(intent);
    } catch (ActivityNotFoundException e) {
        Log.e(TAG, "There was an error opening the custom tab " + e);
    } catch (NullPointerException e) {
        Log.e(TAG, "There was an error opening the custom tab " + e);
    } catch (SomeOtherException e) {
        // Show some dialog
    }
}

你可以这样做:

public void openCustomTab(Context context, @Nullable Uri uri) {
    Intent intent = buildIntent(context, uri);
    try {
        context.startActivity(intent);
    } catch (ActivityNotFoundException e | NullPointerException e) {
        Log.e(TAG, "There was an error opening the custom tab " + e);
    } catch (SomeOtherException e) {
        // Show some dialog
    }
}

2.1.4 Using try-catch over throw exception

在exception出现的地方使用try-catch块增加代码可读性
在代码中error发生的地方就处理,这样不管是debug还是更改error处理都很容易。

2.1.5 不要使用垃圾回收器

不能保证什么时候垃圾回收器会被调用,也不能保证垃圾回收器将在什么时候调用.
大部分情况下,在有良好的异常处理的情况下,你可以做你需要做的。
如果你实在需要,定义一个close()方法(或者类似的)并在方法调用时严格证明(毛线意思啊)
查看InputStreamfor作为例子.
在这种情况下是可以的,但是不需要从垃圾回收器中输出一个短小的日志信息,也不需要输出大量日志.

2.1.6 完全限制方式导包

导包时,使用全包格式,例如:
不要这样导包:

import android.support.v7.widget.*;

而是要这样:

import android.support.v7.widget.RecyclerView;

2.1.7 去掉无用的包引入

通常从一个类中移除代码意味着一些引入的包夜不在需要了。
这种情况下,不需要导入的包应该和代码一起移除掉。

2.2 Java样式规则

2.2.1 属性定义和命名

所有的字段都应该在文件顶部定义,遵循如下规则:

  • private, non-static 字段不应该用“m”做前缀,像如下的例子是正确的:

    userSignedIn, userNameText, acceptButton
    而不是这样:
     mUserSignedIn, mUserNameText, mAcceptButton

  • 所有其他的字段都用小写字母开头:

    int numOfChildren; String username;

  • static final 字段(静态的)全部大写

    private static final int PAGE_COUNT = 0;

  • 类属性命名没有显示任何信息的不应该适用,比如:

    int e; //number of elements in the list
    为什么一开始不给属性一个有意义的名字,而给一段comment呢?
    int numberOfElements;
    如上这样不就很好了嘛

2.2.1.2 View属性名称

当为一个界面控件定义一个类属性时,view应该作为这个属性的后缀,比如:

View
Name
TextView usernameView
Button acceptLoginView
ImageView profileAvatarView
RelativeLayout profileLayout

我们这样命名view以便我们可以知道这个类属性和什么资源关联.

比如, 给定像这样的类属性命名:

usernameView,userAvatarView或者userProfieLayout
这些命名很清晰的表明其对应的资源

以前,控件属性的命名通常用控件类型来结尾(比如acceptLoginButton),但是控件经常改变而且很容易忘记到java类中去更新变量的名称.

2.2.2 命名属性时不要包含容器类型

根据上一条的规则,同样我们应该避免在创建集合变量时使用集合类型来命名.比如,假如我们有一个使用arrayList包含userIds的列表:
使用:

List userIds = new ArrayList<>();
不要使用:
List userIdList = new ArrayList<>();

当集合容器改变类型后,如上的命名可能会经常忘记去更改 - 就像控件命名那样,所以没有必要包含容器类型.
容器变量正确的命名应该包含足够的变量信息.

2.2.3 避免相似的命名

使用相似的名称来命名变量,方法或者类时,会使其他开发者在阅读您的代码时迷惑.比如:

hasUserSelectedSingleProfilePreviously
hasUserSelectedSignedProfilePreviously
很难第一眼就可以区分出上面两个变量是干什么的.使用更清晰的方式命名变量可以使得其他开发者更容易通过变量名理解您的代码.

2.2.4 数字连续命名

当Android Studio自动为我们产生代码,这样很容易给我们留下问题,特别是当它产生糟糕的命名时.比如,这样就很不好:

public void doSomething(String s1, String s2, String s3)
不阅读代码的话很难理解如上这个方法中的参数是做什么的.
public void doSomething(String userName, String userEmail, String userId)
这样就容易理解得多了.我们可以根据这个更容易理解的方法参数去阅读代码了

2.2.5 可读的命名

在对属性,方法和类命名时,应该遵循如下规则:

  1. 可 读:有效的命名意味着我们可以立刻通过名称就理解,减少译解名称的认知负担.
  2. 可拼写:在您尝试对命名很糟糕的名称发音时,可拼写的命名可以避免笨拙的对话.
  3. 可搜索:没有比在一个类中搜索一个方法或者变量时发现名称拼写错误或者命名很糟糕.当我们想找到一个关于查找用户的方法时,直接搜索字符串 ‘search’ 就应该保护这个方法的结果.
  4. 不要使用匈牙利标记法:匈牙利标记法和上面三条冲突,不要使用.

2.2.6 将缩写词(那些将所有字母都大写的词)作为单词使用

在任意类名,变量名中使用的缩写词都应该作为单词使用.比如:

Do
Don’t
setUserId setUserID
String uri String URI
int id int ID
parseHtml parseHTML
generateXmlFile generateXMLFile

2.2.7 避免对齐变量声明

任何变量的声明都不应该使用特殊的对齐格式,比如:
这样就很好:

private int userId = 8;
private int count = 0;
private String username = "hitherejoe";

不要这样做:

private String username = "hitherejoe";
private int userId      = 8;
private int count       = 0;

这样产生了很多空白让代码难于阅读.

2.2.8 使用空白符进行缩进

对于语句块,应该使用4个空白符缩进:
if (userSignedIn) {
count = 1;
}

在自动换行时,应该使用8个空白符缩进:

String userAboutText =
        "This is some text about the user and it is pretty long, can you see!"

2.2.9 If-Statement语句

2.2.9.1 使用标准的大括号样式

大括号应该与其前面的代码放置在同一行。例如,避免下面这样的代码出现:

  class SomeClass
  {
      private void someFunction()
      {
          if (isSomething)
          {

          }
          else if (!isSomethingElse)
          {

          }
          else
          {

          }
      }
  }

取而代之应该这样:

  class SomeClass {
      private void someFunction() {
          if (isSomething) {

          } else if (!isSomethingElse) {

          } else {

          }
      }
  }

这不仅是没有必要增加额外的一行,而它还会让读取代码变得更加容易

2.2.9.2 Inline if-clauses 内联if从句

有时使用单行if语句是有意义的。例如:

  if (user == null) return false;

然而,它仅适用于简单的操作。像下面这样的代码会更适合使用大括号:

  if (user == null) throw new IllegalArgumentExeption("Oops, user object is required.");

2.2.9.3  Nested if-conditions 嵌套的if条件语句

在可能的情况下,if语句的条件应该合并,避免过于复杂的嵌套,例如:

推荐:

  if (userSignedIn && userId != null) {

  }

避免这样:

  if (userSignedIn) {
      if (userId != null) {

      }
  }

这会使得代码更加容易阅读,并且从嵌套子句中移除不必要的额外的行数。

2.2.9.4 Ternary Operators 三元运算

在适当的情况下,三元运算符能够用来简化操作。

例如,下面的代码很容易阅读:

  userStatusImage = signedIn ? R.drawable.ic_tick : R.drawable.ic_cross;

它比下面的代码占用更少的行数:

  if (signedIn) {
      userStatusImage = R.drawable.ic_tick;
  } else {
      userStatusImage = R.drawable.ic_cross;
  }

注意:在有些情况下三元运算符不应该使用。如果if语句的逻辑过于复杂或者包含了大量的字符,这时应该使用标准的大括号样式。

2.2.10 Annotations 注解

2.2.10.1 Annotation practices 注解用法

从《Android code style guidelines》中获悉:

@Override: @Override注解必须使用在当重写方法时候的声明或者实现父类时。例如,如果你使用 @inheritdocs文档标签,并且派生一个类(而不是一个接口),对于重写的父类方法你也必须使用 @Override注解。

@SuppressWarnings: @SuppressWarnings注解应该仅使用在不可能清除警告的情况下,如果一个警告通过了“不可能消除”测试, @SuppressWarnings注解必须使用,以便在代码中确保所有的警告反映实际问题。

有关注解指引的更多信息可以在这里找到。

注解应该使用在可能需要的地方。例如,可使用 @Nullable注解已免出现属性为空的情况。例如:

  @Nullable TextView userNameText;
  private void getName(@Nullable String name) { }

2.2.10.2 Annotation style 注解样式

应用在方法或者类的注解应该总是在声明中定义,并且每一项只能一行:

  @Annotation
  @AnotherAnnotation
  public class SomeClass {
    @SomeAnotation
    public String getMeAString() {

    }
  }

当在属性上使用注解时,应确保注解与属性在同一行,例如:

  @Bind(R.id.layout_coordinator) CoordinatorLayout coordinatorLayout;
  @Inject MainPresenter mainPresenter;

它会使得声明阅读起来更加容易。例如,在声明 '@Inject SomeComponent mSomeName' 可读为'inject this component with this name'(利用这个名字注入组件)。

2.2.11 Limit variable scope 限制变量的作用域

局部变量的作用域应保持在最低限度(《Effective Java》第29条建议)。这样做的话,将会提高代码的可读性和可维护性,同时减少出错的可能性。所有要使用的每一个变量都应该在语句块中声明。

局部变量应当在其第一次使用处声明。几乎每一个局部变量的声明都应该包含一个初始化。如果你还没有足够的信息来合理地初始化变量,你应该推迟声明直到你需要的时候。-摘取自《Android code style guidelines》

2.2.12 Unused elements 无用的元素

所有无用的属性、导入、方法和类应该从代码中移除,除非有特殊的用途保留这些。

2.2.13 Order Import Statements 导入声明

因为我们使用的是Android Studio,因此导入都是自动的按序导入。然而,在一些情况下并非如此,因此应按照下面的顺序导入:

            1.Android imports

            2.Imports from third parties

            3.java and javax imports

            4.Imports from the current Project

注意:1.每个组的导入应按照字母的顺序排列,大写字母排在小写字母之前(Z排在a之前)

            2.在各个组之间应该空一行(android, com, JUnit, net, org, java, javax)

2.2.14 Logging 日志

日志通常在开发过程中用于记录有用的错误消息或者其他可能有用的信息。

Log
Reason
Log.v(String tag, String message) verbose
Log.d(String tag, String message) debug
Log.i(String tag, String message) information
Log.w(String tag, String message) warning
Log.e(String tag, String message) error

我们做日志记录时可以设置一个标示,这个标示是一个静态的final属性,放置在类的顶部,例如:

  private static final String TAG = MyActivity.class.getName(); 

所有的调试日志不应该出现在发布的版本中,另一方面,信息、警告和错误日志只有在需要的时候保持开启。

  if (BuildConfig.DEBUG) {
    Log.d(TAG, "Here's a log message");
  }

注意:Timber是使用起来比较好的日志方式,当我们需要保持一个TAG的引用时,它会为我们处理日志的标示。(看不懂这句话)

2.2.15 Field Ordering 属性排序

在类文件顶部声明的任何属性都应该按下列的排序规则进行排序:

         1.Enums                              枚举类型

         2.Constants                        常量

         3.Dagger Injected fields          Dagger注入的属性

         4.Butterknife View Bindings    Butterknife绑定的view

         5.private global variables         私有变量

         6.public global variables           公共变量

例如:

  public static enum {
      ENUM_ONE, ENUM_TWO
  }

  public static final String KEY_NAME = "KEY_NAME";
  public static final int COUNT_USER = 0;

  @Inject SomeAdapter someAdapter;

  @BindView(R.id.text_name) TextView nameText;
  @BindView(R.id.image_photo) ImageView photoImage;

  private int userCount;
  private String errorMessage;

  public int someCount;
  public String someString;

使用上述的排序规则有助于保持字段声明的分组,从而增加双方的位置和字段的可读性

2.2.16 Class member ordering 类成员排序

为了提高代码的可读性,组织类成员在一个合乎逻辑的方式中是非常的重要,请按下列的排序方式去实现:

         1.Constants                        常量

         2.Fields                       属性

         3.Constructors                            构造方法

         4.Override methods and callbacks (public or private) 继承的方法和回调(公共或者私有)

         5.Public methods              公共方法

         6.Private methods            私有方法

         7.Inner classes or interfaces   内部类或者接口

例如:

  public class MainActivity extends Activity {
      private int count;
      public static newInstance() { }
      @Override
      public void onCreate() { }
      public setUsername() { }
      private void setupUsername() { }
      static class AnInnerClass { }
      interface SomeInterface { }
  }

在Android框架中任何生命周期的方法应该在其相应的生命周期中排序,例如:

  public class MainActivity extends Activity {

      // Field and constructors

      @Override
      public void onCreate() { }

      @Override
      public void onStart() { }

      @Override
      public void onResume() { }

      @Override
      public void onPause() { }

      @Override
      public void onStop() { }

      @Override
      public void onRestart() { }

      @Override
      public void onDestroy() { }

     // public methods, private methods, inner classes and interfaces
  }

2.2.17 Method parameter ordering 方法的参数排序

当定义方法时,参数应该按照下列的规则排序:

  public Post loadPost(Context context, int postId);
  public void loadPost(Context context, int postId, Callback callback);

Context上下文参数应放在第一位,并且Callback回调参数放置在最后

2.2.18 String constants, naming, and values 字符串常量、命名和值

 当使用字符串常量时,其应该修饰为静态final并且遵循下列规则:

2.2.19 Enums 枚举

枚举的使用仅仅在实际需要用到时。如果另外一种方法可行,此时应该选择更好的方式去实现它,例如:

相对于下面这样:

  public enum SomeEnum {
      ONE, TWO, THREE
  }

更推荐这样做:

  private static final int VALUE_ONE = 1;
  private static final int VALUE_TWO = 2;
  private static final int VALUE_THREE = 3;

2.2.20 Arguments in fragments and activities 在fragment和activity中的参数

当我们使用Intent或者Bundle传递数据时,值的键必须使用下面定义的约定:

Activity

传递数据到一个activity必须使用一个KEY的引用,像下面这样定义:

  private static final String KEY_NAME = "com.package.name.activity.KEY_NAME";

Fragment

传递数据到一个fragment必须使用一个EXTRA的引用,像下面这样定义:

  private static final String EXTRA_NAME = "EXTRA_NAME";

当创建fragment或者activity的新实例涉及到传递数据时,我们应该提供一个静态的方法来获取新的实例,传递的数据作为参数。例如:

Activity

  public static Intent getStartIntent(Context context, Post post) {
      Intent intent = new Intent(context, CurrentActivity.class);
      intent.putParcelableExtra(EXTRA_POST, post);
      return intent;
  }

Fragment

  public static PostFragment newInstance(Post post) {
      PostFragment fragment = new PostFragment();
      Bundle args = new Bundle();
      args.putParcelable(ARGUMENT_POST, post);
      fragment.setArguments(args)
      return fragment;
  }

2.2.21 Line Length Limit 行长度限制

代码的行数字符长度最好不要超过100个字符,这样代码的可读性会更高。有时为了实现上述要求,我们需要做的:

         1.提取数据到一个局部变量

         2.提取代码逻辑到外部的方法

         3.将一段较长的代码换行显示

         注意:对于代码的注释和导入声明,超过100个字符的限制是可以的。

2.2.21.1 Line-wrapping techniques 换行技巧

当涉及到换行时,有一些情况我们应该保持与格式化代码的一致性。

运算符换行

当我们需要在一个运算公式换行时,需要在运算符前面换行:

  int count = countOne + countTwo - countThree + countFour * countFive - countSix
          + countOnANewLineBecauseItsTooLong;

如果需要,你可以直接在“=”后换行:

  int count =
          countOne + countTwo - countThree + countFour * countFive + countSix;

方法链

当涉及到链接方法,每个方法的调用都应该另起一行:

不要下面这样:

  Picasso.with(context).load("someUrl").into(imageView);

取而代之应这样:

  Picasso.with(context)
          .load("someUrl")
          .into(imageView);

长参数

对于一个含有长参数的方法,我们在适当的情况下应该换行。例如当声明一个方法时我们应该在最后一个参数的逗号处换行:

  private void someMethod(Context context, String someLongStringName, String text,
                              long thisIsALong, String anotherString) {               
  }      
当调用这个方法时,我们应该在每个参数的逗号后面换行:
  someMethod(context,
          "thisIsSomeLongTextItsQuiteLongIsntIt",
          "someText",
          01223892365463456,
          "thisIsSomeLongTextItsQuiteLongIsntIt");

 

2.2.22 Method spacing(方法间间距)

在同一个类中,方法与方法只需要留有一行的间隙,如下:

public String getUserName() {

    // Code

}

 

public void setUserName(String name) {

    // Code

}

 

public boolean isUserSignedIn() {

    // Code

}

2.2.23 Comments(注释)

2.2.23.1 Inline comments(行内注释 or 内敛注释)

必要的时候,内敛注释是为了解释给读者特定代码段的意思。在代码比较复杂的情况下才添加注释,大多数时候,代码应该以浅显易懂的方式写出来,而不用添加注释。

(注意:代码注释不是非得有,但最好有,注释尽量保持在100字符以内)

2.2.23.2 JavaDoc Style Comments(java文档的注释风格)

方法的名字应该起的和该方法的功能相对应,有时可以提供JavaDoc风格的注释。方法名起的好会帮助读者更好的理解方法的功能,同时也会让读者明白传入方法中参数的作用。

/**

 * Authenticates the user against the API given a User id.

 * If successful, this returns a success result

 *

 * @param userId The user id of the user that is to be authenticated.

 */

2.2.23.3 Class comments(类注释)

在创建类注释时,它们应该是有意义的,有描述性的,必要的时候使用超链接。如下:

/**

  * RecyclerView adapter to display a list of {@link Post}.

  * Currently used with {@link PostRecycler} to show the list of Post items.

  */

不要写初创作者信息,因为以后会有很多人在这个类上修修补补,写上作者信息是没有任何意义的。

/**

  * Created By Joe 18/06/2016

  */

2.2.24 Sectioning code(分段代码)

2.2.24.1 Java code(java代码)

如果对代码做了“分段”,应该使用下面的方法完成,如下:

public void method() { }

 

public void someOtherMethod() { }

 

/********* Mvp Method Implementations  ********/

 

public void anotherMethod() { }

 

/********* Helper Methods  ********/

 

public void someMethod() { }

不能像下面这样:

public void method() { }

 

public void someOtherMethod() { }

 

// Mvp Method Implementations

 

public void anotherMethod() { }

这样会更容易定位类中方法。

2.2.24.2 Strings file(字符串文件)

字符串资源文件string.xml中分段注释如下:

// User Profile Activity

<string name="button_save">Save</string>

<string name="button_cancel">Cancel</string>

 

// Settings Activity

<string name="message_instructions">...</string>

这样写不仅可以让字符串文件看起来整洁,还能在需要更改它们时更容易找到。

2.2.24.3 RxJava chaining(RxJava链接)

当进行异步操作时,每一步操作都应该在遇到“.”号之前另起一行,如下:

return dataManager.getPost()

            .concatMap(new Func1<Post, Observable<? extends Post>>() {

                @Override

                 public Observable<? extends Post> call(Post post) {

                     return mRetrofitService.getPost(post.id);

                 }

            })

            .retry(new Func2<Integer, Throwable, Boolean>() {

                 @Override

                 public Boolean call(Integer numRetries, Throwable throwable) {

                     return throwable instanceof RetrofitError;

                 }

            });

这样会使读者更容易理解接下来的异步操作。

2.2.25 Butterknife(Butterknife)

2.2.25.1 Event listeners(事件监听者)

如有可能,尽量使用ButterKnife绑定监听。举个栗子,可以用ButterKnife替换传统的点击事件:

mSubmitButton.setOnClickListener(new View.OnClickListener() {

    public void onClick(View v) {

        // Some code here...

    }

  };

换成如下:

@OnClick(R.id.button_submit)

public void onSubmitButtonClick() { }

2.3 XML Style Rules(XML文件中样式规则)

2.3.1 Use self=-closing tags(使用单标记)

在xml布局中,如果一个viwe没有任何子view,那么就应该使用单标记。

用这个:

<ImageView

    android:id="@+id/image_user"

    android:layout_width="90dp"

    android:layout_height="90dp" />

不用这个:

<ImageView

    android:id="@+id/image_user"

    android:layout_width="90dp"

    android:layout_height="90dp">

</ImageView>

2.3.2 Resource naming(资源命名)

所有的资源命名规则都应该是小写和下划线的组合,如下:

2.3.2.1 ID naming(id命名)

所有的id命名规则都应该用元素作为前缀。

Element

Prefix

ImageView

image_

Fragment

fragment_

RelativeLayout

layout_

Button

button_

TextView

text_

View

view_

例如:

<TextView

    android:id="@+id/text_username"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content" />

注意:如果一个布局中一种类型的view只有一种,比方toolbar,那么可以直接起名叫toolbar

2.3.2.2 Strings(字符串)

所有的字符串名字应该以该应用的当前功能页面作为前缀,如下:

Screen

String

Resource Name

Registration Fragment

“Register now”

registration_register_now

Sign Up Activity

“Cancel”

sign_up_cancel

Rate App Dialog

“No thanks”

rate_app_no_thanks

如果没法像上面一样命名,咱们可以用下面的方法:

Prefix

Description

error_

Used for error messages

title_

Used for dialog titles

action_

Used for option menu actions

msg_

Used for generic message such as in a dialog

label_

Used for activity labels

需要注意以下两点:

1、同一个的字符串资源不能在多个文件中共享使用。如果其中的一个页面字符串发生改变也会造成另一个页面的改变从而产生问题。每个页面使用单独的字符串资源会给将来省去很多麻烦。

2、字符串资源必须放在字符串资源文件中,不能写在布局或者类中。

2.3.2.3 Styles and themes(风格 & 主题)

当定义风格和主题时,每个单词应该大写开头。如下:

AppTheme.DarkBackground.NoActionBar

AppTheme.LightBackground.TransparentStatusBar

ProfileButtonStyle

TitleTextStyle

2.3.3 Attributes ordering(属性排序)

定义属性不能只为了看起来整洁,同时能够在布局中快速找到属性位置。以下是基本规则:

1、viwe的id

2、风格

3、布局的宽高

4、别的布局属性,按照字母顺序排序

5、剩下的属性,按照字母顺序排序

如下:

<Button

    android:id="@id/button_accept"

    style="@style/ButtonStyle"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_alignParentBottom="true"

    android:layout_alignParentStart="true"

    android:padding="16dp"

    android:text="@string/button_skip_sign_in"

    android:textColor="@color/bluish_gray" />

注意:在Android studio中快速格式化快捷键是:cmd + shift + L

这样做,当布局文件发生变化时,可以通过xml属性快速定位。

2.4 Tests style rules(测试风格规则)

2.4.1 Unit tests(单元测试)

所有测试类起名字都应该和他们被测试的类相对应,并且以Test作为后缀,如下:

Class

Test Class

DataManager

DataManagerTest

UserProfilePresenter

UserProfilePresenterTest

PreferencesHelper

PreferencesHelperTest

所有的测试方法应该用@Test进行注释,测试方法应该用下面的模板:

@Test

public void methodNamePreconditionExpectedResult() { }

举个栗子,如果我们想检测一个使用无效电子邮件地址名叫signUp()方法时,测试方法应该使用如下的:

@Test

public void signUpWithInvalidEmailFails() { }

测试应该将重点放在测试方法赋予的功能名称上面,如果在你的测试方法中还有别的情况需要考虑,这些额外的需要测试的情况应该分到它专门的测试方法中。

如果一个类中包含许多不同的方法,测试应该在多个测试类中进行拆分-这样有助于测试更易于维护和定位。例如,一个数据库工具类有时候会分解成如下几个测试类:

DatabaseHelperUserTest

DatabaseHelperPostsTest

DatabaseHelperDraftsTest

2.4.2 Espresso tests(功能测试框架Espresso)

每个Espresso测试类一般都对应一个Activity,所以命名时应该和对应的Activity相一致,其次是测试,如下:

Class

Test Class

MainActivity

MainActivityTest

ProfileActivity

ProfileActivityTest

DraftsActivity

DraftsActivityTest

当使用Espresso API的时候,方法应该换行从而可以让声明更加宜读,举例如下:

onView(withId(R.id.text_title))

        .perform(scrollTo())

        .check(matches(isDisplayed()))

这种风格的链接调用不仅可以让我们每行不超过100个字符,同时也可以让Espresso测试中的链接更加易读。

3. Gradle Style(Gradle风格)

3.1 Dependencies(依赖)

3.1.1 Versioning(版本控制)

如果一个版本号在多个依赖中多被使用,那么应该在依赖的范围内定义成一个变量,如下:

final SUPPORT_LIBRARY_VERSION = '23.4.0'

compile "com.android.support:support-v4:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:recyclerview-v7:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:support-annotations:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:design:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:percent:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:customtabs:$SUPPORT_LIBRARY_VERSION"

将来如果需要更新依赖,那么只需要更新版本号的变量就可以很轻松的控制所有依赖的版本号。

3.1.2 Grouping(分组)

依赖应该以包名来分组,各个组之间应该有一定的间隙,如下:

compile "com.android.support:percent:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:customtabs:$SUPPORT_LIBRARY_VERSION"

 

compile 'io.reactivex:rxandroid:1.2.0'

compile 'io.reactivex:rxjava:1.1.5'

 

compile 'com.jakewharton:butterknife:7.0.1'

compile 'com.jakewharton.timber:timber:4.1.2'

 

compile 'com.github.bumptech.glide:glide:3.7.0'

 

Compile、testCompile、androidTestCompile依赖同样应该分组到相对应的组别中,如下:

// App Dependencies

compile "com.android.support:support-v4:$SUPPORT_LIBRARY_VERSION"

compile "com.android.support:recyclerview-v7:$SUPPORT_LIBRARY_VERSION"

 

// Instrumentation test dependencies

androidTestCompile "com.android.support:support-annotations:$SUPPORT_LIBRARY_VERSION"

 

// Unit tests dependencies

testCompile 'org.robolectric:robolectric:3.0'

这两种方法都可以很容易的找到特定的依赖关系,需要时,它保证依赖的声明既干净又整洁。

3.1.3 Independent Dependencies(独立的依赖关系)

依赖只能应用在应用或者目的测试中,确保使用compile,testCompile,androidTestCompile来编译它们。例如,robolectric依赖只能被用来做单元测试,它应该如下:

testCompile 'org.robolectric:robolectric:3.0'


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值