Android知识程序员Android技术知识

Android开发基础规范(一)

2016-09-22  本文已影响232人  码农突围

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

一、工程相关

//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.

//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

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


二、代码相关

//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,只能让人迷惑。
当catch一个异常时,我们总是需要输出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);
    }
}

这里我们有如下的方式处理出错:

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处理,这样是很危险的。
如果有人在你调用的代码里添加了一个新的类型的异常,编译器不会帮你认识到你需要处理这个不同的错误类型。这是你代码里很难发现的错误处理方式。
大多数情况下,你不应该用相同的处理方式来处理不同的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 不要使用垃圾回收器


2.1.6 完全限制方式导包


2.1.7 去掉无用的包引入

2.2 Java样式规则

2.2.1 属性定义和命名

2.2.1.2 View属性名称

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

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

View Name
TextView mUserNameView
Button mAcceptLoginButton
ImageView mProfileAvatarView
RelativeLayout mProfileLayout

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

2.2.3 避免相似的命名

2.2.4 数字连续命名

2.2.5 易读的命名

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

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 使用空格符进行缩进

//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语句

//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 {

          }
      }
  }

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

  if (userSignedIn && userId != null) {

  }

避免像下面这样:

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

      }
  }

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

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》中获悉:

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

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

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

    }
  }

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

@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 限制变量的作用域


2.2.12 Unused elements 无用的元素


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

注意:

//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 (错误)

我们做日志记录时可以设置一个标示,这个TAG是一个静态的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");
}
上一篇下一篇

猜你喜欢

热点阅读