最近一段时间,随着公司业务规模的扩大,很多移动端Android项目一起上马,同时引进了大量开发人员. 开发人员水平良莠不齐,开发习惯也各不相同. 因为项目时间紧迫,所以对各种<<代码规范>>和公司研发部的<<项目规范>>都执行的不到位,造成项目沟通,维护和后期运营很大的成本浪费. 研发阶段的代码规范问题不再多说,有很多成熟的自动化检测产品,大部分研发人员也轻车熟路. 今天以我们公司的<<Android项目开发规范>>为例,来说一下项目的自动化,标准化构建及如何简洁的实施,说一下思路, 抛砖引玉.
公司的<<Android项目开发规范>>一共8页,两千多字.如下:
- Java代码开发规范(变量命名,方法的命名,包命名,类和接口命名)
-
res/layout
文件夹命名规范:
res/layout中文件命名规范:- 一个activity对应一个主layout.
- 名称为"activity_activity名称.xml". 例如LoginActivity.java对应activity_login.xml
- 子页面以其主要功能,继续向下细化.如activity_login_dialog.xml
-
res/drawable
文件命名规范:
res/drawable中文件命名规范:- 小写字母和下划线“_”组合命名.
- 图片如果有点击效果则必须以_f结尾. 如btn_login.png对应btn_login_f.png
- 其他命名规则按照设计部内部习惯,自行定义.
- 开发人员创建的selector文件命名规则如下"select_图片名. 如btn_login.png对应select_btn_login.png
- xml规范
- id全部以字母和下划线“_”组合命名.小写字母开头.
- 规则为"所属activity名称_控件类型_功能". 如登录界面的注册按钮对应login_btn_reg. 控件类型说明:button对应btntextView对应txtListView对应list....
- 字符串先在Strng.xml中注册再调用
- dp,sp代替pix
- id全部以字母和下划线“_”组合命名.小写字母开头.
- 类注释:
- 所有的类文件开头、必须要有类的主要作用的简单说明
- 类创建日期
- 作者信息
- 版本改动,更新内容,更新人
- 方法注释
- 类该方法作用是什么?
- @param 各个参数说明
- 异常处理。@throws
- @return 方法返回值、代表的意义
- 使用增强的for循环
- 删除未用到的import引用
- 为if/while/for/do增加大括号
- 移除所有未使用的变量,方法,局部变量
- 移除所有无意义的类型强转
- 缩进:不允许使用Tab进行缩进,使用空格进行缩进,推荐缩进为2空格。
- 空行
- 空行将逻辑相关的代码段分隔开,以提高可读性。
- 一个源文件的两个片段(section)之间
- 类声明和接口声明之间
- 两个方法之间
- 方法内的局部变量和方法的第一条语句之间
- 一个方法内的两个逻辑段之间,用以提高可读性
- ..................
每个入职的开发人员都要仔细研读,项目开发过程中要严格遵守, 所有代码每周由团队负责人审核,查看是否遵循了规范.从总体效果上来说此规范带来的效益还是很高,即便是新手其文件结构及代码风格都不错, 代码的修改,二次开发,修复bug,人员交接等成本都比较低. 但是开发人员在开发过程中,要注意的条条框框太多,代码频繁被打回,各种前置要求导致开发成本提高,习惯培养也不是一两天可以形成...... 规范意味着规则,规则意味着可以配置化,代码化,所以我们通过了一些优化步骤,把此规范简化成了以下三条:
- 导入企业IDE通用配置文件
- 项目创建后,使用企业AndroidProjectBuild.xml的初始化功能来初始化项目.(自动创建文件,目录,增加配置等)
- 项目后期,使用企业AndroidProjectBuild.xml的构建功能来重构项目.(自动整理资源,优化项目等)
本文结尾提供了三个配置文件的下载,已针对Android项目做了规范化处理,各位也可根据自己的需求,新增或修改配置.导入步骤:Eclipse工具栏上选择Window -> Preferences -> Java -> Code Style ->import导入对应的配置文件->edit可根据自己需求,进行二次编辑. 所有开发人员配置完成后,写出的代码从风格上来说就像是一个人.在代码同步时也可以避免不少冲突,更新问题.更重要的是不用再一条一条去看编码规范了, 一个快捷键搞定.
coco_cleanUp.xml: 清理代码功能,在java代码和xml文件中,按Alt+shift+S选择Cleanup. 会自动完成以下工作:
- 为if/else,while等控制语句,增加{}.
- 代码中的for循环会自动修改为增强型for循环.
- 删除所有没用到的imports,私有变量,私有方法,私有构造方法,局部变量
- 所有变量定义,都会被整理置于类顶部,并排序.
- 无意义的类型强转都会取消.
- 忘记添加的'@Override',@Deprecated' 会自动添加.
- 会自动导入用到的类,相当于Ctrl+shift+O(取决于Organize imports中的配置)
- ...................
coco_codeFormat.xml: 格式化代码功能,在java代码和xml文件中,按Ctrl+shift+F. 会自动完成以下工作:
- 删除空行
- 方法之间增加换行
- 每个变量声明独占一行,变量名是否左对齐
- 可定义每行的最大长度
- 定义代码缩进风格,比如空格缩进,tab缩进,空格缩进数量,case,switch,if,for等语句缩进风格.
- 变量,数组,方法等各元素之间间距.
- 注释的风格,一行多长,是否左对齐,是否换行等.
- .......................
coco_codetemplates.xml: 代码模板. 会自动完成以下工作:
- 创建类时,自动添加类版本,创建时间,作者,类名,版权.
- 选中类,变量,方法按下Alt+Shift+J会自动添加对应注释.
- 可自行编辑注释模板.
<?xml version="1.0" encoding="UTF-8"?> <!-- V1.3 作者fay,Android项目构建文件,ant build文件,适用于架构部UML生成的Android项目,在项目创建完成后初始化使用, 完成功能有 1.(构建功能)为所有类添加标准化注释 2.(初始化功能)自动生成部分XML布局文件 3.(构建功能)自动抽取布局文件中的所有字符串,并在String.xml中注册 4.(构建功能)自动修改布局文件中id命名,并更新项目 5.(初始化功能)自动创建图片的selector文件 6.(初始化功能)actvity在Manifest中注册 7.名为reduce的target不会自动执行,此任务将删除drawable中所有未使用到的图片 8.名为autoFormat的target不会自动执行,此任务将以公司的cleanUp.xml,codeFormat.xml两个配置全盘格式化当前项目代码包括src下的全部文件,layout下的全部文件. ........ --> <project name="buildAndroidProject" default="searchActivity"> <property name="path_layout" value="res/layout/" /> <property name="path_src" value="src" /> <taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" classpath="ant-contrib-1.0b3.jar" /> <!--判断activity对应的布局XML文件是否已生成过--> <target name="detectFile"> <condition property="fileIsExists"> <and> <available file="res/layout/activity_*.xml" /> </and> </condition> </target> <!--查找到所有Activity并形成列表--> <target name="searchActivity" depends="detectFile" unless="fileIsExists"> <fileset id="activitysPath" dir="${path_src}"> <include name="**/*Activity*" /> </fileset> <pathconvert property="activityNameList" refid="activitysPath"> <mapper> <chainedmapper> <flattenmapper /> <globmapper casesensitive="no" from="*.java" to="*.xml" /><!--把后缀修改为xml--> <scriptmapper language="javascript"><!--Activity名称转换为小写--> self.addMappedName(source.toLowerCase()); </scriptmapper> <filtermapper> <replacestring from="activity" to="" /> </filtermapper> </chainedmapper> </mapper> </pathconvert> <fileset id="activityPathListID" dir="${path_src}"> <include name="**/*Activity*" /> </fileset> <pathconvert property="activityPathList" refid="activityPathListID"> <mapper> <chainedmapper><!--去目录--> <regexpmapper from="[\/\\]?src[\/\\](.+).java" to="\1" /> <packagemapper from="*" to="*" /> </chainedmapper> </mapper> </pathconvert> <foreach delimiter=";" list="${activityNameList}" param="activityName" target="createLayout" /> <foreach delimiter=";" list="${activityPathList}" param="activityPath" target="insertMainFest" /> <antcall target="searchSelect" /> </target> <!--为每个Activity创建对应的布局文件--> <target name="createLayout"> <touch file="${path_layout}activity_${activityName}" /> <echo file="${path_layout}activity_${activityName}" message="<?xml version='1.0' encoding='utf-8'?> <RelativeLayout xmlns:android='http://schemas.android.com/apk/res/android' android:layout_width='match_parent' android:layout_height='match_parent' > </RelativeLayout>" /> </target> <!--为每个Activity注册--> <target name="insertMainFest"> <replace file="AndroidManifest.xml" token="</application>" value="<activity android:name='${activityPath}' android:configChanges='keyboardHidden|screenSize' android:label='labelName'/></application>" /> </target> <!--遍历所有图片,筛选出需要自动生成selector的图片--> <target name="searchSelect"> <fileset id="selectImgNameID" dir="res"> <include name="**/*_f*" /> </fileset> <pathconvert property="selectImgNames" refid="selectImgNameID"> <mapper> <chainedmapper> <flattenmapper /> <regexpmapper from="(\S*)_f" to="\1" /> </chainedmapper> </mapper> </pathconvert> <foreach delimiter=";" list="${selectImgNames}" param="selectImgList" target="createSelect" /> </target> <!-- 自动生成selector --> <target name="createSelect"> <touch file="res/drawable/select_${selectImgList}.xml" /> <echo file="res/drawable/select_${selectImgList}.xml" message="<?xml version='1.0' encoding='utf-8'?> <selector xmlns:android='http://schemas.android.com/apk/res/android'> <item android:drawable='@drawable/${selectImgList}_f' android:state_pressed='true'></item> <item android:drawable='@drawable/${selectImgList}' android:state_pressed='false'></item> <item android:drawable='@drawable/${selectImgList}'/> </selector>" /> </target>......... </project>
碰巧前些天看IBM的Open source,注意到eclipse写着遵循OSGI规范,写build文件时想了起来,顺手google了一下,还真找到了. STEP2的功能8其实就是把STEP1整合进去了.最终利用ant直接调动eclipse的JavaCodeFormatter接口,就可以执行代码格式化操作了.
ex: eclipse -vm <path to virtual machine> -application org.eclipse.jdt.core.JavaCodeFormatter -config <configFile> <files>
更多的eclipse外调方法,可查看
http://grepcode.com/file/repository.grepcode.com/java/eclipse.org/3.6/org.eclipse.jdt/core/3.6.0/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java?av=f