首页 > 代码库 > Android开发基础规范(二)
Android开发基础规范(二)
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52614696
前言:Android中一些开发规范,避免给自己和别人少留坑。
二、代码相关
2.2.15 Field Ordering 属性排序
在类文件顶部声明的任何属性都应该按下列的排序规则进行排序:
- 1.Enums (枚举类型)
- 2.Constants (常量)
- 3.Dagger Injected fields (Dagger注入的属性)
- 4.Butterknife View Bindings (Butterknife绑定的view)
- 5.private global variables (private成员变量)
- 6.public global variables (public成员变量)
例如:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public static enum {
ENUM_ONE, ENUM_TWO
}
public static final String KEY_NAME = "KEY_NAME";
public static final int COUNT_USER = 0;
@Inject SomeAdapter mSomeAdapter;
@BindView(R.id.text_name) TextView mNameText;
@BindView(R.id.image_photo) ImageView mPhotoImage;
private int mUserCount;
private String mErrorMessage;
public int mSomeCount;
public String mSomeString;
使用上述的排序规则有助于保持字段声明的分组,从而增加字段的可读性
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
例如:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public class MainActivity extends Activity {
private int mStepCount;
public static newInstance() { }
@Override
public void onCreate() { }
public void setColor(Color color) { }
private int getId() { }
static class AnInnerClass { }
interface SomeInterface { }
}
在Android框架中任何生命周期的方法应该在其相应的生命周期中排序,例如:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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 方法的参数排序
当定义方法时,参数应该按照下列的规则排序:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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 枚举
枚举的使用仅仅在实际需要用到时。如果另外一种方法可行,此时应该选择更好的方式去实现它,例如:
相对于下面这样:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public enum SomeEnum {
ONE, TWO, THREE
}
更推荐这样做:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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”;
- 传递数据到一个activity必须使用一个KEY的引用,像下面这样定义:
- Fragment
- 传递数据到一个fragment必须使用一个EXTRA的引用,像下面这样定义:
private static final String EXTRA_NAME = “EXTRA_NAME”;
- 传递数据到一个fragment必须使用一个EXTRA的引用,像下面这样定义:
当创建fragment或者activity的新实例涉及到传递数据时,我们应该提供一个静态的方法来获取新的实例,传递的数据作为参数。例如:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
//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 换行技巧
当涉及到换行时,有一些情况我们应该保持与格式化代码的一致性。
- 运算符换行
当我们需要在一个运算公式换行时,需要在运算符前面换行:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
int count = countOne + countTwo - countThree + countFour * countFive - countSix
+ countOnANewLineBecauseItsTooLong;
如果需要,你可以直接在“=”后换行:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
int count =
countOne + countTwo - countThree + countFour * countFive + countSix;
- 方法链
当涉及到方法链时(这个比较流行,建议写方法链,RxJava几乎都是),每个方法的调用都应该另起一行:
不要下面这样:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
Picasso.with(context).load("someUrl").into(imageView);
取而代之应这样:
Picasso.with(context)
.load("someUrl")
.into(imageView);
- 长参数
对于一个含有长参数的方法,我们在适当的情况下应该换行。例如当声明一个方法时我们应该在最后一个参数的逗号处换行:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
private void someMethod(Context context,
String someLongStringName,
String text,long
thisIsALong, String anotherString) {
}
当调用这个方法时,我们应该在每个参数的逗号后面换行:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
someMethod(context,
"thisIsSomeLongTextItsQuiteLongIsntIt",
"someText",
01223892365463456,
"thisIsSomeLongTextItsQuiteLongIsntIt");
2.2.22 Method spacing(方法间间距)
在同一个类中,方法与方法之间只需要留有一行的空白,如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public String getUserName() {
// Code
}
public void setUserName(String name) {
// Code
}
public boolean isUserSignedIn() {
// Code
}
2.2.23 Comments(注释)
2.2.23.1 Inline comments(行内注释)
必要的时候,写注释,其他情况下最好不要写注释,从方法名或者成员变量上就能看出做什么。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.
*/
public class XXX {
}
- 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.
*/
public class RecyclerView {
}
不要写初创作者信息,因为以后会有很多人在这个类上改来改去,写上作者信息是没有任何意义的。
/**
* Created By yuiop 22/09/2016
*/
public class XXX {
}
2.2.24 Sectioning code(分段代码)
2.2.24.1 Java code(java代码)
如果对代码做了“分段”,应该使用下面的方法完成,如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public void method() { }
public void someOtherMethod() { }
/********* MVP Method Implementations ********/
public void anotherMethod() { }
/********* Helper Methods ********/
public void someMethod() { }
不能像下面这样:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
public void method() { }
public void someOtherMethod() { }
// Mvp Method Implementations
public void anotherMethod() { }
这样会更容易定位类中方法。
2.2.24.2 Strings file(字符串文件)
字符串资源文件string.xml中分段注释如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
// User Profile Activity
<string name="button_save">Save</string>
<string name="button_cancel">Cancel</string>
// Settings Activity
<string name="message_instructions">...</string>
这样写不仅可以让string文件看起来整洁,还能在需要更改它们时更容易找到。
2.2.24.3 RxJava chaining(RxJava链接)
当进行异步操作时,每一步操作都应该在遇到“.”号之前另起一行,如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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替换传统的点击事件:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
mSubmitButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Some code here...
}
};
换成如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
@OnClick(R.id.button_submit)
public void onSubmitButtonClick() { }
2.3 XML Style Rules(XML文件中样式规则)
2.3.1 Use self=-closing tags(使用单标记)
在xml布局中,如果一个viwe没有任何子view,那么就应该使用单标记。
用这个:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
<ImageView
android:id="@+id/image_user"
android:layout_width="90dp"
android:layout_height="90dp" />
不用这个:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
<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_ |
例如:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
<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 | ResourceName |
---|---|---|
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
当定义style和theme时,每个单词应该大写开头。如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
AppTheme.DarkBackground.NoActionBar
AppTheme.LightBackground.TransparentStatusBar
ProfileButtonStyle
TitleTextStyle
2.3.3 Attributes ordering(属性排序)
定义属性不能只为了看起来整洁,同时能够在布局中快速找到属性位置。以下是基本规则:
- 1、viwe的id
- 2、style
- 3、布局的宽高
- 4、其他的布局属性,按照字母顺序排序
- 5、其他的属性,按照字母顺序排序
如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
<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属性快速定位。
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52614696
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() { }
举例,如果我们想测试一个使用不正确邮箱登录的功能,测试方法应该使用如下的:
@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测试中的链接更加易读。
Gradle Style(Gradle风格)
3.1 Dependencies(依赖)
3.1.1 Versioning
如果一个版本号在多个依赖中多被使用,那么应该在依赖的范围内定义成一个变量,如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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(分组)
- 依赖应该以包名来分组,各个组之间应该有一定的间隙,如下:
//create by 逆流的鱼yuiop on 2016/9/22
//blog地址:http://blog.csdn.net/hejjunlin
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‘
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
Android开发基础规范(二)