程序员人生 网站导航

Android开发基础规范(一)

栏目:综合技术时间:2016-10-22 13:05:58

转载请把头部出处链接和尾部2维码1起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52602487

前言:Android中1些开发规范,避免给自己和他人少留坑。

1、工程相干

  • 1.1 工程结构
    当进行提交代码的工作时,工程应当保持以下的目录结构:
//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin - 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 类文件
      任何定义的类都应当使用驼峰命名格式,比如:
//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin AndroidActivity, NetworkHelper, UserFragment, PerActivity

任何继承自android组件的类都应当使用组件名称来结尾,比如:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin UserFragment, SignUpActivity, RateAppDialog, PushNotificationServer, NumberView
  • 使用驼峰格式命名易于浏览。
  • 用android组件名称结尾的继承类能够清楚的标识出类的用处,比如,如果要去查找修改RegistrationDialog时,那末这个命名使得定位这个类文件非常方便。

    • 1.2.2 资源文件
      • 当命名资源文件时,应当只使用小写字母和下划线替换空格,例如:
        activity_main, fragment_user, item_post
        在你查找布局文件时,这样命名一样使得定位文件很方便。
      • 在使用android studio中,布局的package中的文件是按字母顺序排列的,这样意味activity,fragment和其他的layout是按组分类放置的,所以你知道从哪里去开始找1个文件了。
      • 不但如此,用组件名称开头的布局文件可以很清晰的表示这个布局文件是被那类组件使用。
  • 1.2.2.1 Drawable 文件

    • 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文件应当使用对应的前缀,以下:

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

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中这个命名约定仍然可以帮助我们将类似的组织到1起
并清晰的标识出这1文件用作甚么
比如, 命令1个资源为“button_cancel”不能标识任何信息
这是1个selector资源呢还是1个圆角按钮背景呢?
正确的命名可以去除所有的引发的模糊不清.
在创建selector不同状态资源时,也应当使用对应的命名下标:

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

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组件的名称作为文件名的前缀,比如:

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

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
      正确的方式是避免没有处理的异常,以下:
//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin public void setUserId(String id) { try { mUserId = Integer.parseInt(id); } catch (NumberFormatException e) { } }

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

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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个信息给用户,提示他们这里出错了
  • 设置了1个可能的默许值
  • 抛出了1个适合的异常

2.1.2 不要catch最大的异常(Exception):

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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处理,这样是很危险的。
如果有人在你调用的代码里添加了1个新的类型的异常,编译器不会帮你认识到你需要处理这个不同的毛病类型。这是你代码里很难发现的毛病处理方式。
大多数情况下,你不应当用相同的处理方式来处理不同的exception.
以下,catch期望的异常并正确的处理:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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
在异常运行相同的代码的地方,他们应当增加可读性和避免代码复制。比如,你可能会像以下这样处理异常:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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 } }

你可以这样做:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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 不要使用垃圾回收器

  • 不能保证甚么时候垃圾回收器会被调用,也不能保证垃圾回收器将在甚么时候调用.
  • 大部份情况下,在有规范的异常处理的情况下,你可以做你需要做的。
    如果你实在需要,定义1个close()方法(或类似的)并在方法调用时,提示记得close
  • 以InputStreamfor作为example.
  • 在这类情况下是可以的,但是不需要从垃圾回收器中输出少许日志信息,也不需要输出大量日志.

2.1.6 完全限制方式导包

  • 导包时,使用全包格式,例如:
  • 不要这样导包:
    import android.support.v7.widget.*;
  • 而是要这样:
    import android.support.v7.widget.RecyclerView;

2.1.7 去掉无用的包引入

  • 通常从1个类中移除代码意味着1些之前引入的包也已不需要。
    这类情况下,不需要导入的包应当和代码1起移除掉。

2.2 Java样式规则

2.2.1 属性定义和命名

  • 所有的字段都应当在文件顶部定义,遵守以下规则:
    private, non-static 字段应当用“m”做前缀,像以下的例子是正确的:
    mUserSignedIn, mUserNameText, mAcceptButton

  • 所有其他的字段都用小写字母开头:
    int numOfChildren; String username;
    static final 字段(静态的)全部大写
    private static final int PAGE_COUNT = 0;

  • 类属性命名没有显示任何信息的不应当适用,比如:
    int e; //number of elements in the list
  • 为何1开始不给属性1个成心义的名字,而给1段comment呢?
    int numberOfElements;

2.2.1.2 View属性名称

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

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

View Name
TextView mUserNameView
Button mAcceptLoginButton
ImageView mProfileAvatarView
RelativeLayout mProfileLayout
  • 我们这样命名view以便我们可以知道这个类属性和甚么资源关联.
  • 比如, 给定像这样的类属性命名:
    mUserNameView,mUserAvatarView或mUserProfieLayout
  • 这些命名很清晰的表明其对应的资源
  • 之前,控件属性的命名通经常使用控件类型来结尾(比如acceptLoginButton),但是控件常常改变而且很容易忘记到java类中去更新变量的名称.

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

  • 根据上1条的规则,一样我们应当避免在创建集合变量时使用集合类型来命名.比如,假设我们有1个使用arrayList包括userIds的列表:
  • 不要使用:
    List userIds = new ArrayList<>();
  • 使用:
    List userIdList = new ArrayList<>();
  • 容器变量正确的命名应当包括足够的变量信息.

2.2.3 避免类似的命名

  • 使用类似的名称来命名变量,方法或类时,会使其他开发者在浏览您的代码时迷惑.比如:
    hasUserSelectedSingleProfilePreviously
    hasUserSelectedSignedProfilePreviously
  • 很难第1眼就能够辨别出上面两个变量是干甚么的.使用更清晰的方式命名变量可使得其他开发者更容易通过变量名理解您的代码.

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个类中搜索1个方法或变量时发现名称拼写毛病或命名很糟.当我们想找到1个关于查找用户的方法时,直接搜索字符串 ‘search’ 就应当保护这个方法的结果.
  • 不要使用匈牙利标记法:匈牙利标记法和上面3条冲突,不要使用.

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

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

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

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

2.2.7 避免对齐变量声明

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

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin private int userId = 8; private int count = 0; private String username = "hitherejoe";

不要这样做:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin private String username = "hitherejoe"; private int userId = 8; private int count = 0;

这样产生了很多空白,让代码难于浏览.

2.2.8 使用空格符进行缩进

  • 对语句块,应当使用4个空格符缩进:

    if (userSignedIn) {
    count = 1;
    }
    在自动换行时,应当使用8个空格符缩进:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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 使用标准的大括号样式
    大括号应当与其前面的代码放置在同1行。例如,避免下面这样的代码出现:
//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin class SomeClass { private void someFunction() { if (isSomething) { } else if (!isSomethingElse) { } else { } } }

取而代之应当这样:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin class SomeClass { private void someFunction() { if (isSomething) { } else if (!isSomethingElse) { } else { } } }

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

  • 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;

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

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin 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文档标签,并且派生1个类(而不是1个接口),对重写的父类方法你也必须使用 @Override注解。
  • @SuppressWarnings: @SuppressWarnings注解应当仅使用在不可能清除正告的情况下,如果1个正告通过了“不可能消除”测试, @SuppressWarnings注解必须使用,以便在代码中确保所有的正告反应实际问题。
    有关注解指引的更多信息可以在这里找到。
  • 注解应当使用在可能需要的地方。例如,可以使用@Nullable注解已免出现属性为空的情况。例如:
@Nullable TextView userNameText; private void getName(@Nullable String name) { }

2.2.10.2 Annotation style 注解样式
利用在方法或类的注解应当总是在声明中定义,并且每项只能1行:

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin @Annotation @AnotherAnnotation public class SomeClass { @SomeAnotation public String getMeAString() { } }

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

@Bind(R.id.layout_coordinator) CoordinatorLayout mCoordinatorLayout; @Inject MainPresenter mMainPresenter;

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

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

  • 局部变量的作用域应保持在最低限度(《Effective Java》第29条建议)。这样做的话,将会提高代码的可读性和可保护性,同时减少出错的可能性。
  • 所有要使用的每个变量都应当在语句块中声明。
    局部变量应当在其第1次使用途声明。几近每个局部变量的声明都应当包括1个初始化。如果你还没有足够的信息来公道地初始化变量,你应当推延声明直到你需要的时候。

2.2.12 Unused elements 无用的元素

  • 所有没有用的属性、导入、方法和类应当从代码中移除,除非有特殊的用处保存这些。

2.2.13 Order Import Statements 导入声明
由于我们使用的是Android Studio,因此导入都是自动的按序导入。但是,在1些情况下并不是如此,因此应依照下面的顺序导入:

  • 1.Android imports
  • 2.Imports from third parties
  • 3.java and javax imports
  • 4.Imports from the current Project

注意:
- 1.每一个组的导入应依照字母的顺序排列,大写字母排在小写字母之前(Z排在a之前)
- 2.在各个组之间应当空1行(android, com, JUnit, net, org, java, javax)
2.2.14 Logging 日志
日志通常在开发进程中用于记录有用的毛病消息或其他可能有用的信息。

//create by 逆流的鱼yuiop on 2016/9/21
//blog地址:http://blog.csdn.net/hejjunlin

Log Reason
Log.v(String tag, String message) verbose (详细)
Log.d(String tag, String message) debug(调试)
Log.i(String tag, String message) information(普通info)
Log.w(String tag, String message) warning(正告)
Log.e(String tag, String message) error (毛病)

我们做日志记录时可以设置1个标示,这个TAG是1个静态的final属性,放置在类的顶部,例如:
private static final String TAG = MyActivity.class.getName();
所有的调试日志不应当出现在发布的版本中,另外一方面,信息、正告和毛病日志只有在需要的时候保持开启。

//create by 逆流的鱼yuiop on 2016/9/21 //blog地址:http://blog.csdn.net/hejjunlin if (BuildConfig.DEBUG) { Log.d(TAG, "Here's a log message"); }

第1时间取得博客更新提示,和更多android干货,源码分析,欢迎关注我的微信公众号,扫1扫下方2维码或长按辨认2维码,便可关注。

这里写图片描述

如果你觉得好,随手点赞,也是对笔者的肯定,也能够分享此公众号给你更多的人,原创不容易

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐