Android项目和代码规范(译)

译自:project_and_code_guidelines


1.项目规范

1.1工程结构

Android项目应当遵循Android Gradle plugin user guide所定义的Android项目结构规范!一个很好的项目示例:ribot Boilerplate

1.2文件命名

1.2.1 类文件

  • class文件命名规则遵循驼峰式命名:UpperCamelCase。

  • 继承自Android组件的class文件需要以Android组件的名字为后缀,例如:SignInActivity, SignInFragment, ImageUploaderService, ChangePasswordDialog

1.2.2资源文件

  • 资源文件命名规范遵循:小写字母加下划线
1.2.2.1 Drawable 资源文件

Drawable文件命名规范:

Asset TypePrefixExample
Action barab_ab_stacked.9.png
Buttonbtn_btn_send_pressed.9.png
Dialogdialog_dialog_top.9.png
Dividerdivider_divider_horizontal.9.png
Iconic_ic_star.png
Menumenu_menu_submenu_bg.9.png
Notificationnotification_notification_bg.9.png
Tabstab_tab_pressed.9.png

图标的命名规范:

Asset TypePrefixExample
Iconsic_ic_star.png
Launcher iconsic_launcheric_launcher_calendar.png
Menu icons and Action Bar iconsic_menuic_menu_archive.png
Status bar iconsic_stat_notifyic_stat_notify_msg.png
Tab iconsic_tabic_tab_recent.png
Dialog iconsic_dialogic_dialog_info.png

表明选择状态的命名规范:

StateSuffixExample
Normal_normalbtn_order_normal.9.png
Pressed_pressedbtn_order_pressed.9.png
Focused_focusedbtn_order_focused.9.png
Disabled_disabledbtn_order_disabled.9.png
Selected_selectedbtn_order_selected.9.png
1.2.2.2 layout文件命名规范

布局文件名字应该与相应的Android组件的名字相匹配,并且将Android组件的名字放在布局文件的开始,例如:SignInActivity对应的布局文件应该命名为:activity_sign_in.xml.
请看表中的例子:

ComponentClass NameLayout Name
ActivityUserProfileActivityactivity_user_profile.xml
FragmentSignUpFragmentfragment_sign_up.xml
DialogChangePasswordDialogdialog_change_password.xml
AdapterView itemitem_person.xml
Partial layoutpartial_stats_bar.xml

- 当我们给ListView的每一项创建布局的时候,布局应该以item_开始。
- 当上述规则无法满足的时候,比如该布局文件是另一个布局文件的一部分,这时候就应该以partial_开头。

1.2.2.3 Menu File

与layout文件相同,我们命名menu文件也应该与相应地组件名字进行匹配,假如我们要为UserActivity创建一个menu file,它应该命名为:activity_user.xml
这个文件已经在menu的文件目录下,所以不用再包含关键字menu

2.代码规范

2.1 Java语言规范

2.1.1 必须处理异常

绝不能这样做:

void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}

绝对不能因为你认为你的代码不会遇到这个错误或者,这个错误不重要就不去处理这个异常,必须根据不同的情况去处理各种异常。参考…

2.1.2 不要抛出普遍的异常

当代码会抛出各种各样的异常的时候,应该把每一种异常都抛出来,而不是只抛出这些异常的父类:

try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
    // phew, made it all the way
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}

参考…

2.1.3 不要使用finalizer

我们不要使用finalizer,我们无法确定它什么时候被调用或者是否会被调用。参考…

2.1.4 不要导入一个包下的所有类

错误: import foo.*;
正确: import foo.Bar;

2.2 Java风格规范

2.2.1 成员变量的命名和定义
  • private non-static 类型变量以m开头;
  • private static 类型的变量以s开头;
  • 其他类型的变量以小写字母开头
  • static final 类型的变量必须全部使用大写字母;

例如:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}
2.2.2 将首字母缩略词视为一个单词

不要将一个缩略词全部大写:

GoodBad
XmlHttpRequestXMLHTTPRequest
getCustomerIdgetCustomerID
String urlString URL
long idlong ID
2.2.3 使用空格进行代码缩进
  • 代码块的缩进使用4个空格:
if (x == 1) {
    x++;
}
  • 折行的时候使用8个空格:
Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);
2.2.4 使用标准的结构

即:规范的使用大括号:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

不使用大括号的时候,代码体应该简短至一行:

if(condition) body();

不应该这样写:

if(condition)
    body();
2.2.5 注解(Annotations)
2.2.5.1使用注解

根据Android代码风格规范,一些标准的注解使用如下:
* @override: 在重写父类或者接口中的方法时,必须使用这个注解。
* @SuppressWarnings: 当我们不可能去消除一个警告的时候,使用这个注解!这样可以确保所有的警告信息可以真实的反应我们代码中的实际问题!
参考…

2.2.5.2 注解的风格

Classes, Methods and Constructors
当我们在一个类、方法或者是构造方法中使用注解的时候,把注解放在注释的后面,并且每一个注解占据一行。

 /* This is the documentation block about the class */
@AnnotationA
@AnnotationB
public class MyAnnotatedClass { }

Fields
对成员变量使用注解必须全部放在一行,除非到达行末。

@Nullable @Mock DataManager mDataManager;
2.2.6 限制变量的作用域
  • 局部变量应该保持最小的作用域,这样可以提高代码的易读性和可维护性,并且减少代码出错的可能性。
  • 局部变量应该在它第一次使用的地方声明,几乎所有的局部变量都应该初始化,如果你并没有明确的信息去初始化一个局部变量,那么这个局部变量应该推迟声明。
2.2.7 对import声明进行排序

如果你使用Android Studio,那么就不用担心这个问题,Android Studio会自动帮你解决这个问题。如果不是,请按照以下顺序进行声明:
1. Android imports(Android相关的包)
2. Imports from third parties(第三方的包)
3. java and javax
4. Project import (项目内的包)
此外,为了匹配IDE的设置,imports还应该遵循:
* 按照以上顺序声明进行分组(例如:android, com, junit, net, org, java, javax),每组中间大写字母应该在小写字母的前面。
* 每组中间应该有空格分隔开来。

2.2.8 Logging 规范

使用Log类去打印有用的信息:

  • Log.v(String tag, String msg) (verbose)
  • Log.d(String tag, String msg) (debug)
  • Log.i(String tag, String msg) (information)
  • Log.w(String tag, String msg) (warning)
  • Log.e(String tag, String msg) (error)
    一般来说,我们使用类的名字去定义一个static final类型的成员变量作为tag, 例如:
public class MyClass {
    private static final String TAG = MyClass.class.getSimpleName();

    public myMethod() {
        Log.e(TAG, "My error message");
    }
}

所有的Log信息必须在release版本中去除,因为这些可能会丢失一些关键的信息!

2.2.9 类成员的排序

对类的成员进行排序将会提高代码的可读性,我们建议使用下列顺序:

  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 String mTitle;
    private TextView mTextViewTitle;

    public void setTitle(String title) {
        mTitle = title;
    }

    @Override
    public void onCreate() {
        ...
    }

    private void setUpView() {
        ...
    }

    static class AnInnerClass {

    }

}

如果一个类继承自Android的组件,这个类中重写的Android组件的生命周期方法要按照组件的生命周期来写:

public class MainActivity extends Activity {

    //Order matches Activity lifecycle
    @Override
    public void onCreate() {}

    @Override
    public void onResume() {}

    @Override
    public void onPause() {}

    @Override
    public void onDestroy() {}

}
2.2.10 方法参数的顺序

Android开发中经常会遇到传递Context参数的情况,这时候Context参数必须作为第一参数传递。

相反的是Callback必须作为方法的最后一个参数:

// Context always goes first
public User loadUser(Context context, int userId);

// Callbacks always go last
public void loadUserAsync(Context context, int userId, UserCallback callback);
2.2.12 String类型的常量,命名和值

Andorid SDK中会有很多这样的变量:SharedPreferences,Bundle,或者Intent使用键值对,所以我们会创建大量的String常量。
当我们使用这个组件的时候,我们必须定义static final类型的key值,并且它们要有一个恰当的前缀用以提示:

ElementField Name Prefix
SharedPreferencesPREF_
BundleBUNDLE_
Fragment ArgumentsARGUMENT_
Intent ExtraEXTRA_
Intent ActionACTION_

例如:

// Note the value of the field is the same as the name to avoid duplication issues
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";

// Intent-related items use full package name as value
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
2.2.13 Fragments and Activities中的参数

当数据通过Intent或者是BundleActivity或者Fragment中间传递的时候,它们所用到的key值都必须按照上一节的规则。
Activity或者是Fragment想要获取这些参数的时候,它应该提供一个public static的方法以便于去获取相应的Intent

Activity中这个方法通常写作getStartIntent():

public static Intent getStartIntent(Context context, User user) {
    Intent intent = new Intent(context, ThisActivity.class);
    intent.putParcelableExtra(EXTRA_USER, user);
    return intent;
}

Fragment之中则写为newInstance

public static UserFragment newInstance(User user) {
    UserFragment fragment = new UserFragment;
    Bundle args = new Bundle();
    args.putParcelable(ARGUMENT_USER, user);
    fragment.setArguments(args)
    return fragment;
}

注意 1: 这些方法必须放在类的顶部onCreate().

注意 2: 如果我们有这样的方法,那么这些key值都必须使用private进行声明,它们没有必要暴露给额外的类。

2.2.14 限制每一行的长度

代码每一行不应该超过100个字符,如果每一行的长度过长,使用以下两种方式去减少行的长度:
* 提取一些局部变量和方法。
* 使用折行将一行换成多行。

2.2.14.1 折行的策略

没有一种特定的折行方式,但是有一些折行的规则如下:

操作符折行

操作符前折行,例如:

int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
        + theFinalOne;

等号操作符处后面折行

当操作符是=的时候,应该在=后面折行:

int longName =
        anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;

Method chain case

当遇到链式的方法调用的时候,应当在.之前折行:

Picasso.with(context)
        .load("http://ribot.co.uk/images/sexyjoe.jpg")
        .into(imageView);

方法参数过多

方法参数过多应该以每个参数后面的逗号后面折行

loadPicture(context,
        "http://ribot.co.uk/images/sexyjoe.jpg",
        mImageViewProfilePicture,
        clickListener,
        "Title of the picture");
2.2.15 Rxjava链式风格

Rx chains of operators require line-wrapping. Every operator must go in a new line and the line should be broken before the .

public Observable<Location> syncLocations() {
    return mDatabaseHelper.getAllLocations()
            .concatMap(new Func1<Location, Observable<?extends Location>>() {
                @Override
                 public Observable<? extends Location> call(Location location) {
                     return mRetrofitService.getLocation(location.id);
                 }
            })
            .retry(new Func2<Integer, Throwable, Boolean>() {
                 @Override
                 public Boolean call(Integer numRetries, Throwable throwable) {
                     return throwable instanceof RetrofitError;
                 }
            });
}

2.3 XML 风格规范

2.3.1 Use self closing tags

当一个元素不包含内容的时候,必须自闭
This is good:

<TextView
    android:id="@+id/text_view_profile"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

This is bad :

<!-- Don\'t do this! -->
<TextView
    android:id="@+id/text_view_profile"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
</TextView>
2.3.2 资源文件命名

资源id和名称必须全部使用小写字母和下划线。

2.3.2.1 资源ID 命名

id应该以对应的组件名字为前缀,加下划线命名:

ElementPrefix
TextViewtext_
ImageViewimage_
Buttonbutton_
Menumenu_

Image view example:

<ImageView
    android:id="@+id/image_profile"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Menu example:

<menu>
    <item
        android:id="@+id/menu_done"
        android:title="Done" />
</menu>
2.3.2.2 Strings

String文件命名应该以它所属于的模块内容名字为前缀,例如:registration_email_hint or registration_name_hint.若不属于任何模块,则遵循以下规则:

PrefixDescription
error_An error message
msg_A regular information message
title_A title, i.e. a dialog title
action_An action such as “Save” or “Create”
2.3.2.3 Styles and Themes

样式文件名称都使用驼峰式命名。

2.3.3 Attributes ordering

组件的属性排序按照以下顺序

  1. View Id
  2. Style
  3. Layout width and layout height
  4. Other layout attributes, sorted alphabetically
  5. Remaining attributes, sorted alphabetically
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值