转载请把头部出处链接和尾部2维码1起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52602487
前言:Android中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.
//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.1 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、代码相干
//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);
}
}
这里我们有以下的方式处理出错:
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 不要使用垃圾回收器
2.1.6 完全限制方式导包
2.1.7 去掉无用的包引入
2.2.1 属性定义和命名
所有的字段都应当在文件顶部定义,遵守以下规则:
private, non-static 字段应当用“m”做前缀,像以下的例子是正确的:
mUserSignedIn, mUserNameText, mAcceptButton
所有其他的字段都用小写字母开头:
int numOfChildren; String username;
static final 字段(静态的)全部大写
private static final int PAGE_COUNT = 0;
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 |
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 使用空格符进行缩进
对语句块,应当使用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语句
//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从句
2.2.9.3 Nested if-conditions 嵌套的if条件语句
在可能的情况下,if语句的条件应当合并,避免过于复杂的嵌套,例如:
推荐:
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 注解样式
利用在方法或类的注解应当总是在声明中定义,并且每项只能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 限制变量的作用域
2.2.12 Unused elements 无用的元素
2.2.13 Order Import Statements 导入声明
由于我们使用的是Android Studio,因此导入都是自动的按序导入。但是,在1些情况下并不是如此,因此应依照下面的顺序导入:
注意:
- 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维码,便可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也能够分享此公众号给你更多的人,原创不容易