田海立
2012-10-05
Google对Android的编程规范在Code Style Guidelines for Contributors中做了描述,并在Android源码中release了import和Java的配置文件android.importorder与android-formatting.xml。本文分析这些配置文件在Eclipse环境下格式化Android编码规范都做了什么,在Java和XML文件中如何具体体现。
Android源码目录
1)打开Window > Preferences > Java > Code Style;
2)在Organizer Imports中点击Imports,选择android.importorder导入;
3)在Formatter中点击Imports,选择android-formatting.xml导入。
下面讲解这些配置都做了什么,在代码中如何具体体现的。
Google推荐的AndroidJava文件开头import的次序(按照先后)是:
排列原则:
缩进只用空格,不用制表符(TAB)。缩进用4个空格,按下TAB键用4个空格代替。
/**
* Indentation
*/
class Example {
int[] myArray = {
1, 2, 3, 4, 5, 6
};
int theInt = 1;
String someString = "Hello";
double aDouble = 3.0;
void foo(int a, int b, int c, int d, int e, int f) {
switch (a) {
case 0:
Other.doFoo();
break;
default:
Other.doBaz();
}
}
void bar(List v) {
for (int i = 0; i <10; i++) {
v.add(new Integer(i));
}
}
}
enum MyEnum {
UNDEFINED(0) {
void foo() {
}
}
}
@interface MyAnnotation {
int count() default 1;
}
1) 域不用对齐
若对齐的话,则myArray,theInt, someString和aDouble都在同一列上对齐。
2)类体内部的声明全都缩进
Class Example内的定义[#5 ~ #29]相对classExample[#4]都有缩进
3)枚举的声明要缩进
UNDEFINED(0) [#33]前面有缩进
4)枚举内的常量要缩进
voidfoo() [#34]前面有缩进
5)注解的声明要缩进
intcount()[#39]前面有缩进
6)方法/构造体内的语句要缩进
方法foo和bar内的语句[#16 ~ #22, #26 ~ #28]都有缩进
7)程序块内的语句要缩进
for循环内的v.add(newInteger(i))[#27]有缩进
8)switch内的语句要缩进
switch内的语句[#17 ~ #21]相对switch有缩进
9)case内的语句要缩进
Other.doFoo()[#18]相对于case;Other.doBaz()[#21]相对于default都有缩进
10)break语句要缩进
break[#19]相对于case有缩进
11)空白行不用缩进
域和方法之间的空白行[#8, #10, #12, #14, #24]是没有缩进的
/**
* Braces
*/
interface Empty {
}
enum MyEnum {
UNDEFINED(0) {
void foo() {
}
}
}
@interfaceSomeAnnotationType {
}
class Example {
SomeClass fField = new SomeClass() {
};
int[] myArray = {
1, 2, 3, 4, 5, 6
};
int[] emptyArray = new int[] {};
Example() {
}
void bar(int p) {
for (int i = 0; i <10; i++) {
}
switch (p) {
case 0:
fField.set(0);
break;
case 1: {
break;
}
default:
fField.reset();
}
}
}
1)类或接口的声明跟左大括号在同一行上
#4 Empty以及 #17 Example后面{的位置
2)匿名类的声明跟左大括号在同一行上
#18 SomeClass后面{的位置
3)构造体的声明跟左大括号在同一行上
#27 Example()后面{的位置
4)方法的声明跟左大括号在同一行上
#9 foo和#30 bar后面{的位置
5)枚举的声明跟左大括号在同一行上
#7 MyEnum 后面{的位置
6)枚举常量体跟左大括号在同一行上
#8 UNDEFINED(0) 后面{的位置
7)注解类型的声明跟左大括号在同一行上
#14 SomeAnnotationType后面{的位置
8)程序块跟左大括号在同一行上
#31 for后面{的位置
9)case语句中的程序块跟左大括号在同一行上
#37 case 1后面{的位置
10)switch语句跟左大括号在同一行上
#33 switch后面{的位置
11)数组的初始化常量跟左大括号在同一行上
#21和#25 {的位置
class MyClass implements I0, I1, I2 {
}
AnonClass = new AnonClass() {
void foo(Some s) {
}
};
·类的左大括号的前面加空格;
·匿名类的左大括号的前面加空格;
·implements语句中逗号的前面,不加空格;
·implements语句中逗号的后面,加上空格;
int a = 0, b = 1, c= 2, d = 3;
·多个域声明中逗号的前面,不加空格;
·多个域声明中逗号的后面,加上空格。
int a = 0, b = 1, c= 2, d = 3;
·多个临时变量声明中逗号的前面,不加空格;
·多个临时变量声明中逗号的后面,加上空格;
MyClass() throws E0, E1 {
this(0, 0, 0);
}
MyClass(int x, int y, int z) throws E0, E1 {
super(x, y, z, true);
}
·左小括号的后面,不加空格;
·右小括号的前面,不加空格;
·小括号内为空,则它们之间不加空格;
·左大括号前面,加上空格;
·参数列表中逗号之前,不加空格;
·参数列表中逗号之后,加上空格;
·throws语句中逗号之前,不加空格;
·throws语句中逗号之后,加上空格。
void foo() throws E0, E1 {
};
void bar(int x, int y) throws E0, E1 {
}
void format(Strings, Object... args) {
}
·左小括号的前面,不加空格;
·左小括号的后面,不加空格;
·右小括号的前面,不加空格;
·小括号内为空,则它们之间不加空格;
·左大括号前面,加上空格;
·参数列表中逗号之前,不加空格;
·参数列表中逗号之后,加上空格;
·可变参数列表省略号之前,不加空格;
·可变参数列表省略号之后,加上空格;
·throws语句中逗号之前,不加空格;
·throws语句中逗号之后,加上空格。
label: for (int i = 0; i < list.length; i++) {
for (int j = 0; j < list[i].length; j++)
continue label;
}
·冒号之前,不加空格;
·冒号之后,加上空格
@Annot(x = 23, y = -3)
public class A {
}
·‘@’之后,不加空格;
·左小括号的前面,不加空格;
·左小括号的后面,不加空格;
·逗号前面,不加空格;
·逗号后面,加上空格;
·右小括号的前面,不加空格
enum MyEnum {
GREEN(0, 1), RED() {
void process() {
}
}
}
·声明中左大括号的前面[#1],加上空格;
·常量之间的逗号[#2 RED前]前面,不加空格;
·常量之间的逗号[#2 RED前]后面,加上空格;
·常量参数的左小括号[#2 GREEN后]前面,不加空格;
·常量参数的左小括号[#2 GREEN后]后面,不加空格;
·常量参数的小括号[#2 RED后]中间为空,括号之间不加空格;
·常量参数之间的逗号[#2 GREEN()里面]前面,不加空格;
·常量参数之间的逗号[#2 GREEN()里面]后面,加上空格;
·常量参数的右小括号[#2 GREEN()后]前面,不加空格;
·常量体左大括号[#2 RED后]前面,加上空格。
@interface MyAnnotation {
String value();
}
@interface OtherAnnotation {
}
·‘@’之前,不加空格;
·‘@’之后,不加空格
·左大括号的前面,加上空格;
·注解类型成员的左小括号的前面,不加空格;
·注解类型成员的小括号的之间,不加空格;
if (true) {
return 1;
} else {
return 2;
}
·左大括号前面,加上空格;
·右大括号后面,加上空格。
if (condition) {
return foo;
} else {
return bar;
}
·左小括号前加上空格;
·左小括号后不加空格;
·右小括号前不加空格【左大括号前的空格是规则#4.2.1】
for (int i = 0, j = array.length; i < array.length; i++, j--) {
}
for (String s : names) {
}
·左小括号前加上空格;
·左小括号后不加空格;
·右小括号前不加空格【左大括号前的空格是规则#4.2.1】
·初始化语句的逗号前不加空格;
·初始化语句的逗号后加上空格
·增量语句的逗号前不加空格;
·增量语句的逗号后加上空格
·语句之间的分号前不加空格;
·语句之间的分号后加上空格;
·冒号前面加上空格;
·冒号后面加上空格。
switch (number) {
case RED:
return GREEN;
case GREEN:
return BLUE;
case BLUE:
return RED;
default:
return BLACK;
}
· case和default的冒号(‘:’)前不加空格;
·左括号(‘(’)和左大括号(‘{’)前都加上空格;
·左括号(‘(’)后和右括号(‘)’)前都不加空格。
while (condition) {
}
;
do {
} while (condition);
·左括号前加上空格;
·左括号后不加空格;
·右括号前不加空格【#1左大括号前的空格是规则#4.2.1】
synchronized (list) {
list.add(element);
}
·左括号前加上空格;
·左括号后不加空格;
·右括号前不加空格【左大括号前的空格是规则#4.2.1】
try {
number = Integer.parseInt(value);
} catch (NumberFormatException e) {
}
·左括号前加上空格;
·左括号后不加空格;
·右括号前不加空格【左大括号前的空格是规则#4.2.1】
assert condition : reportError();
冒号前后都加上空格
return (o);
括号表达式前加上空格
throw (e);
括号表达式前加上空格
foo();
bar(x, y);
String str = new String();
Point point = new Point(x, y);
MyClass() throws E0, E1 {
this(0, 0, 0);
}
MyClass(int x, int y, int z) throws E0, E1 {
super(x, y, z, true);
}
·左括号的前后都不加空格;
·右括号前不加空格;
·空的参数的左右括号之间不加空格;
·方法调用时多个参数之间分割的逗号前面不加空格,逗号后面加空格;
·对象申请时多个参数之间分割的逗号前面不加空格,逗号后面加空格;
·显示调用构造函数时多个参数之间分割的逗号前面不加空格,逗号后面加空格;
List list = new ArrayList();
int a = -4 + -9;
b = a++ / --number;
c += 4;
boolean value = true && false;
赋值操作(=)前后都加上空格。【注意:‘+=’是一个操作数】
List list = new ArrayList();
int a = -4 + -9;
b = a++ / --number;
c += 4;
boolean value = true && false;
·二元操作(#2的‘+’;#3的‘/’;#5的‘&&’)前后都加上空格;
·一元操作(#2 ‘4’和‘9’前面的‘-’)前后都不加空格【示例中‘-’前的空格不是这个规则里的】;
·前置操作的(#3的‘--number’)前后都不加空格【示例中‘--’前的空格不是这个规则里的】;
·后置操作的(#3的‘a++’)前后都不加空格【示例中‘++’后的空格不是这个规则里的】。
result = (a * (b + c + d) * (e + f));
左括号前,左括号后和右括号前都不加空格【示例中左括号前的空格不是这个规则里的】
String s = ((String) object);
·右括号后加上空格;
·左括号后和右括号前都不加空格。
String value = condition ? TRUE : FALSE;
问号前,问号后,冒号前,冒号后都要加上空格
int[] array0 = new int[] {};
int[] array1 = new int[] {
1, 2, 3
};
int[] array2 = new int[3];
array[i].foo();
·左中括号前不加空格;
·左右中括号中间不加空格
示例中:arrayX前的‘[]’
·左中括号前后都不加空格;
·右中括号前不加空格;
·空的左右中括号中间不加空格;
示例中:等号‘=’后面的‘[]’
·左大括号前后都加上空格;
·右大括号前加上空格;
·逗号前不加空格;
·逗号后加上空格;
·空的大括号中间不加空格
·左中括号前后都不加空格;
·右中括号前面不加空格
Map map = newHashMap();
x. foo();
classMyGenericType {
}
Map, Y extendsK, ? super V>> t;
/**
* Blank Lines
*/
package foo.bar.baz;
import java.util.List;
import java.util.Vector;
import java.net.Socket;
public class Another {
}
public class Example {
public static class Pair {
public String first;
public String second;
// Between here...
// ...and here are 10 blank lines
};
private LinkedList fList;
public int counter;
publicExample(LinkedList list) {
fList = list;
counter = 0;
}
public void push(Pair p) {
fList.add(p);
++counter;
}
public Object pop() {
--counter;
return (Pair)fList.getLast();
}
}
1)包声明之前有一空白行[#4]
2)包声明之后有一空白行[#6]
3)import声明之前有一空白行[#6]
4)import各个分组之间有一空白行[#9]
5)import声明之后有一空白行[#11]
6)类声明之间有一空白行[#14]
1)第一个声明之间无空白行[#15 & #16之间]
2)相同分类声明之前有一空白行[#24, #28]
3)成员类声明之前有一空白行
4)域声明之前有一空白行[#18, #24, #26]
5) 方法声明之前有一空白行[#28,#33, #38]
6) 方法内的开始处没有空白行[#29和#30之间;#34与#35之间;#39与#40之间]
/**
* New Lines
*/
public class Empty {
}
class Example {
static int[] fArray = {
1, 2, 3, 4, 5
};
Listener fListener = new Listener() {
};
@Deprecated
@Override
public void bar(@SuppressWarnings("unused") int i) {
@SuppressWarnings("unused")
int k;
}
void foo() {
;
;
label: do {
} while (false);
for (;;) {
}
}
}
enum MyEnum {
UNDEFINED(0) {
}
}
enum EmptyEnum {
}
@interface EmptyAnnotation{
}
1)类体内为空,插入新行[#5是另起的一行]
2)匿名类体内为空,插入新行[#13是另起的一行]
3)方法内为空,插入新行
4)空的程序块,插入新行[#26是另起的一行;#28是另起的一行]
5)标号后面不插入新行[#25 do与label在同一行]
6)在空的枚举声明中,插入新行[#38是另起的一行]
7)在空的枚举常量体中,插入新行[#34是另起的一行]
8)在空的注解体中,插入新行[#41是另起的一行]
9)在文件结尾,插入新行[#42是另起的一行]
1)数组初始化体的左大括号后,插入新行[#9是另起的一行]
2)数组初始化体的右大括号前,插入新行[#10是另起的一行]
空的语句放在新行上[#24是另起的一行]
1)对成员的注解之后,插入新行[#16 & #17都是另起的一行]
2)对参数的注解之后,不插入新行[#17 int i与@SuppressWarnings("unused")在同一行]
3)对临时变量的注解之后,插入新行[#19是另起的一行]
/**
* If...else
*/
class Example {
void bar() {
do {
} while (true);
try {
} catch (Exception e) {
} finally {
}
}
void foo2() {
if (true) {
return;
}
if (true) {
return;
} else if (false) {
return;
} else {
return;
}
}
void foo(int state) {
if (true)
return;
if (true)
return;
else if (false)
return;
else
return;
}
}
1)if语句的else之前,不插入新行[#20& #22的else与‘}’在同一行]
2)try语句的catch之前,不插入新行[#9的catch与‘}’在同一行]
3)try语句的finally之前,不插入新行[#10的finally与‘}’在同一行]
4)do语句的while之前,不插入新行[#7的while与‘}’在同一行]
5)#29的‘then’语句与#28的if在不同行,#31的‘then’语句与#30的if在不同行;
6)#35的else语句与#34的else在不同行;
7)#20和#32的else if中‘else与‘if’在同一行;
8)‘return’或‘throw’语句不需要在一行上[#16与#15在两行上]
/**
* Element-value pairs
*/
@MyAnnotation(value1 = "this isan example", value2 = "of an annotation", value3 = "withseveral arguments", value4 = "by Haili TIAN ([email protected])")
class Example {
}
注解不换行:value1、value2、value3和value4都在同一行上。
/**
* 'extends' clause
*/
class Example extends
OtherClass {
}
/**
* 'implements' clause
*/
class Example implements I1,
I2, I3 {
}
/**
* Parameters
*/
class Example {
Example(int arg1, int arg2,
int arg3, int arg4,
int arg5, int arg6) {
this();
}
Example() {
}
}
/**
* 'throws' clause
*/
class Example {
Example() throws FirstException,
SecondException,
ThirdException {
returnOther.doSomething();
}
}
/**
* Declaration
*/
class Example {
public final synchronizedjava.lang.String a_method_with_a_long_name() {
}
}
/**
* Parameters
*/
class Example {
void foo(int arg1, int arg2,
int arg3, int arg4,
int arg5, int arg6) {
}
}
/**
* 'throws' clause
*/
class Example {
int foo() throws FirstException,
SecondException,
ThirdException {
returnOther.doSomething();
}
}
/**
* Constants
*/
enum Example {
CANCELLED, RUNNING, WAITING, FINISHED
}
enum Example {
GREEN(0, 255, 0), RED(
255, 0, 0)
}
/**
* 'implements' clause
*/
enum Example implements A, B,
C {
}
/**
* Constant arguments
*/
enum Example {
GREEN(0, 255, 0), RED(
255, 0, 0)
}
/**
* Arguments
*/
class Example {
void foo() {
Other.bar(
100,
nested(200, 300, 400,
500, 600, 700,
800, 900));
}
}
/**
* Qualified invocations
*/
class Example {
int foo(Some a) {
return a.getFirst();
}
}
/**
* Explicit constructor invocations
*/
class Example extends AnotherClass {
Example() {
super(100, 200, 300,400, 500,
600, 700);
}
}
/**
* Object allocation arguments
*/
class Example {
SomeClass foo() {
return new SomeClass(100,200,
300, 400, 500, 600,
700, 800, 900);
}
}
/**
* Qualified object allocation arguments
*/
class Example {
SomeClass foo() {
return SomeOtherClass.new SomeClass(
100, 200, 300, 400, 500);
}
}
/**
* Binary expressions
*/
class Example extends AnotherClass {
int foo() {
int sum = 100 + 200 + 300 + 400
+ 500 + 600 + 700 + 800;
int product = 1 * 2 * 3 * 4 * 5
* 6 * 7 * 8 * 9 * 10;
boolean val = true && false
&& true && false
&& true;
return product / sum;
}
}
/**
* Conditionals
*/
class Example extends AnotherClass {
int Example(boolean Argument) {
return argument ?100000
: 200000;
}
}
/**
* Array initializers
*/
class Example {
int[] fArray = {
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12
};
}
/**
* Assignments
*/
class Example {
private static final String string ="TextTextText";
void foo() {
for (int i = 0; i <10; i++) {
}
String s;
s = "TextTextText";
}
}
/**
* Compact 'if else'
*/
class Example {
int foo(int argument) {
if (argument == 0)
return 0;
if (argument == 1)
return 42;
else
return 43;
}
}
配置起什么用,没看懂!
/**
* An example for comment formatting. This example is meant to illustrate the various possibilities offered by Haili TIAN in order to format comments.
*/
package mypackage;
/**
* This is the comment for the example interface.
*/
interface Example {
// This is a long comment with white space that should be split in multiple
// line comments in case the linecomment formatting is enabled
int foo3();
// void commented() {
// System.out.println("indented");
// }
// void indentedCommented() {
// System.out.println("indented");
// }
/* block comment on first column */
int bar();
/*
* These possibilities include:- Formatting of header
* comments.
- Formatting of Javadoc tags
*/
int bar2(); // This is along comment that should be split in multiple line
// comments in case the linecomment formatting is enabled
/**
* The following is some sample code whichillustrates source formatting
* within javadoc comments:
*
*
* public class Example {
* final int a = 1;
*
* final boolean b = true;
* }
*
*
* Descriptions of parameters and returnvalues are best appended at end of
* the javadoc comment.
*
* @param a The first parameter. For an optimum result, this should be an
* odd number between 0 and 100.
* @param b The second parameter.
* @return The result of the foo operation, usually within 0 and 1000.
*/
int foo(int a, int b);
}
#37 ~ #43
#47是插入的行
#49的odd相对#48的a缩进了4个空格。
#48和#50的描述与参数在同一行。
Javadoc注释形式见#33~ #52
块注释形式见#26~ #29
#15, #16 和#17是行注释,且‘//’与原程序之间的空格仍旧保持。
#1, #2和#3的头注释保持不变。
#23是块注释,与程序有相同的缩进,不是缩进到第一列。
注:笔者对行注释验证,发现Eclipse中无论如何设置,基本不会改变其行为。
前面讲了那么多都是针对Java程序的,Android中有大量的XML文件。对XML的格式也要进行排版格式化。
打开Window> Preferences,可以通过两个地方对XML文件进行格式化:
1)XML > XML Files > Editor
对其中的各项设置进行配置
2)Android > Editors
对其中的各项设置进行配置
本文分析了Android编码风格在Eclipse环境中具体实施,通过对Eclipse环境的配置可以方便的格式化Android程序:Java文件和XML文件,特别是Java文件,其配置是基于JDT实现的,所以对Java的方方面面的配置都覆盖了。
但是,只有这些还不够,对一般的Java设计编码原则和Android中推荐的风格还不能完全自动执行,还需要人的参与,依赖于团队风格规范的制定,成员的设计能力和领悟执行能力。下面是这些工具所不能解决的风格和原则: