Android App开发入门与实战
上QQ阅读APP看书,第一时间看更新

第1章 编码规范

1.1 命名规范

1.1.1 Android包命名规范

因为Android包目录的命名会直接影响到整个App工程后期的开发效率和扩展性,所以在创建项目的初期,包目录的命名非常重要。

Android工程本身对包目录命名没有要求,可以将代码文件直接放置在默认目录下,但这样做会导致很多无关文件的堆积,不利于查找及后期维护,所以一般不建议采用这种方式。

Android包目录命名的常用方式有两种:PBL(Package By Layer)和PBF(Package By Feature)。

1. Package By Layer

PBL是按层次划分的,实际上就是按照职能划分,如在根目录里面命名activity、fragment、view、service、db、net、util、bean、base等包名。

例如,activity的职能是管理所有的Activity类,只要这个类是继承自Activity的,都放到这个目录下。以此类推,fragment目录存放所有继承自Fragment的类,view放置自定义的View,net放置网络相关的类,bean放置Bean对象等。

早期的Android App开发常采用图1.1所示的包结构。

接下来我们来分析一下PBL这种命名结构的优缺点。

1)PBL优点

·项目结构简洁明了,上手快。

·适合开发人员不多、项目功能简单、后期变动不大的项目。

2)PBL缺点

(1)低内聚

同一个目录下会有各种功能模块。例如activity目录,其中放置了登录、设置等功能模块;这几个模块本身并没有很强的关联性,却被放置在了一起,导致聚合性降低。

(2)高耦合

这里讲的高耦合是指目录之间的关联性,例如activity目录内的类可能引用到了fragment或者view目录里面的类,导致目录之间的耦合性较高。

(3)影响开发效率

开发一个功能模块,往往需要在不同的包目录之间切换。例如登录模块,需要在activity目录下开发LoginActivity类,而LoginActivity类往往包含了fragment目录下的内容,这时又需要去fragment目录下找到对应的Fragment类来开发,目录之间频繁切换会影响开发效率。同样,修改、调试一个功能也需要进行这样的操作,如果后期项目功能和代码增多,会大大降低开发效率。

2. Package By Feature

PBF是按照功能划分包目录的。以功能模块名称作为目录名,所有与这个功能模块相关的开发都在这个目录内。

以Google I/O 2019 Android App为例,如图1.2所示。

图1.1 PBL包目录结构

图1.2 Google I/O 2019 Android App包目录结构

可以看到,除了与业务无关的模块,如utils这样的通用模块,每一个包目录都对应一个功能模块。

Google的项目采用PBF进行包目录命名,我们来分析一下PBF有哪些优点。

1)高内聚

所有功能都在一个包下完成,以map模块为例,如图1.3所示。

可以看到,map目录下包含了fragment、adapter、viewmodel等。这里需要说明的是,功能模块里面的util一般都是和这个功能模块强相关的,如果是功能模块包目录外的util目录名,一般放置的是与项目相关的util类和能作用于整个或者多个功能模块的util类。

其他包目录以此类推,例如ui包目录下面放置了Base Activity,adapter包目录下面放置了BaseAdapter等。

2)低耦合

包目录之间没有很强的关联性,此模块的功能只需要在对应的包目录下面即可进行开发,除了基础类外,一般不需要引入其他包的类。

3)开发效率高

图1.3 map模块包目录结构

增删改查都只需要在对应的包目录下面操作即可,便于团队开发管理,提升问题排查效率,也方便后续开发人员接手。

4)便于后期组件化转化

如果项目是按照PBF来进行包目录划分的,后期进行组件化改造的时候就会非常方便。可以直接把功能模块独立出来作为一个组件,同时划分好代码边界,对外保留好模块间的访问接口。例如上面的map功能模块,可以将其独立出来作为一个library工程。

1.1.2 Android代码命名规范

以Java语言为例,来说明一下如何制定代码的命名规范。

命名规则约定事项如下。

·代码命名不以下画线和美元符号开头。

·【】表示可选。

1. 类名

采用大驼峰命名法。

(1)命名规则

【功能】 + 【类型】。

(2)举例

Activity类,命名以Activity为后缀,如:LoginActivity。

Fragment类,命名以Fragment为后缀,如:ShareFragment。

Service类,命名以Service为后缀,如:DownloadService。

Dialog类,命名以Dialog为后缀,如:ShareDialog。

Adapter类,命名以Adapter为后缀,如:ProductAdapter。

BroadcastReceiver类,命名以Receiver为后缀,如:PushReceiver。ContentProvider类,命名以Provider为后缀,如:FileProvider。

业务处理类,命名以Manager为后缀,如:UserManager。

解析类,命名以Parser为后缀,如:NewsParser。

工具类,命名以Util为后缀,如:EncryptUtil。

模型类,命名以Bean为后缀,如:GiftBean。

接口实现类,命名以Impl为后缀,如:DeviceImpl。

自定义共享基础类,命名以Base开头,如:BaseActivity。

测试类,命名以它要测试的类的名称开始,以Test结束,如:DeviceImplTest。

(3)抽象类和接口类

抽象类命名后缀为Abstract,如:abstract DeviceAbstract。

接口类命名后缀为Contract,如:interface DeviceContract。

2. 方法名

采用小驼峰命名法。

(1)命名规则

动词或动名词。如:run()、addDevice()。

(2)举例

初始化方法,命名以init开头,如:initView。

按钮点击方法,命名以to开头,如:toLogin。

设置方法,命名以set开头,如:setData。

具有返回值的获取方法,命名以get开头,如:getData。

通过异步加载数据的方法,命名以load开头,如:loadData。

布尔型的判断方法,命名以is、has或check开头,如:isEmpty、checkNull。

对数据进行处理,命名以handle开头,如:handleUserInfo。

弹出提示框,命名以show开头,如:showAgreement。

更新数据,命名以update开头,如:updateUserInfo。

保存数据,命名以save开头,如:saveUserInfo。

重置数据,命名以reset开头,如:resetUserInfo。

删除数据,命名以delete开头,如:deleteUserInfo。

查询数据,命名以query开头,如:queryUserInfo。

移除数据,命名以remove开头,如:removeUserInfo。

3. 变量名

采用小驼峰命名法,变量命名应该简短且有规则。所有变量都要显示地赋值,如int number =0。布尔变量应该包含Is,如IsFirstLogin。

按照不同的变量类型,变量的命名规则有所不同,如下。

(1)类变量(成员变量)

非公有的变量前面要加上小写m;静态变量前面要加上小写s;其他变量以小写字母开头,前面不再加任何前缀,例如Bean类中的属性变量,为了生成的get和set方法名美观可读,有一些IDE已经支持生成get和set方法名时自动去除前缀。

常量、静态变量全大写,采用下画线命名法。


1. public class Demo {
2. public static final int SOME_CONSTANT = 2020;
3. public int publicField = 1;
4. private static Demo sSingleton;
5. int mPackagePrivate;
6. private int mPrivate = 0;
7. protected int mProtected = 10;
8. }

(2)局部变量

变量为一个单词,以小写字母开头。如:GiftBean bean。

(3)参数

参数为一个或多个单词的组合,以小写字母开头。如:fun(int position)、fun(String userName)。

(4)临时变量

临时变量通常被取名为i、j、k、m和n,它们一般用于整型;c、d、e一般用于字符型。如:for (int i = 0; i < len ; i++),for (String c : stringList)。

(5)泛型变量

泛型变量一般用单个大写字母来表示,如果这个泛型是某个类的子类,那么这个大写字母一般取的是父类所代表的这个类含义的首字母。如:interface BasePresenter<V extends BaseView,M extends BaseModel> ,其中V代表View,M代表Model。

(6)控件变量

Android中把很多UI控件作为成员变量,为了和Java的成员变量区分开,UI控件类型的成员变量在遵循前面成员变量命名规范的前提下,后面统一再加上控件名称。如:private TextView mDescriptionTextView。

有些命名规则是在后面加上控件的缩写,缩写不如全名看起来美观,而且不易于理解。

1.1.3 Android资源文件命名规范

1. layout命名

全部小写,采用下画线命名法,使用名词或名词词组。所有Activity或Fragment等的布局名必须与其类名相对应。

(1)命名规则

【类型名】+【模块名】。

(2)举例

MainActivity.java对应activity_main.xml,规则是类名单词倒置,中间用“_”连接,并且单词全部改为小写,如下。

activity_main:Main模块的Activity。

fragment_login:Login模块的Fragment。

dialog_update:Update模块的Dialog。

关于include,由于include的布局一般不属于某个专门的模块,所以用include_代表类型。如果是在某个模块内拆分出来的布局,需要加上这个模块的名称,如下。

include_tips:提供tips布局。

include_im_function:IM模块的功能布局。

关于ListView、RecyclerView或GridView的item的布局命名,用item_代表类型,如下。

item_user_member:User模块下普通会员的item。

item_user_vip:User模块下VIP会员的item。

另外,item如果是表示header或footer的,可以加上_header或_footer后缀,如下。

item_user_header:User模块下下拉刷新的header。

item_user_footer:User模块下下拉刷新的footer。

总之,布局文件的命名需要能直接反映该布局文件的作用范围和功能。

2. layout中的id命名

全部小写,采用下画线命名法。

(1)命名规则

【控件缩写】+【模块名】+【功能名】。

(2)举例


1. <!-- 这是登录模块的密码输入框 -->
2. <TextView
3. android:id="@+id/et_login_password"
4. />
5.
6. <!-- 这是登录按钮 -->
7. <Button
8. android:id="@+id/btn_login_submit"
9. />

有时候为了简洁,layout的id定义得不那么复杂,例如上面的et_login_password可能会写成password。这样有一个问题是,如果项目中存在多个相同的命名,那么查找起来会有些不方便,如图1.4所示的同名id。

图1.4 同名id

在单击main_content这个id名后,系统会弹出对话框提示选择跳转到哪一个layout下面的id。这样会增加开发时间,尤其是在对代码的熟悉程度不够的情况下。而且如果是在SDK中这样去命名,很有可能会导致引用SDK的项目出现资源重名并产生冲突。

3. anim命名

全部小写,采用下画线命名法。

(1)命名规则

【模块名】+【动画类型】+【动画方向】。

如果不限定模块名,表示这个动画是全局通用的。

(2)举例

scale_in.xml:缩小;slide_out.xml:扩大。

fade_in.xml:淡入;fade_out.xml:淡出。

push_down_in.xml:从下方推入;push_down_out.xml:从下方推出。

left_in.xml:从左边进入;left_out.xml:从左边退出。

welcome_zoom_in.xml:欢迎界面放大。

4. mipmap(或drawable)命名

全部小写,采用下画线命名法。

(1)命名规则

【控件缩写】+【模块名】+【功能名】+【状态限定】。

状态限定的内容包括small、big、normal、focus、red、white等,且可以叠加。

(2)举例

btn_main_back.png:Main模块的返回按钮的图片。

btn_main_back_small.png:Main模块的返回按钮的小图片。

btn_main_back_small_pressed.png:Main模块的返回按钮被选中时的小图片。

btn_red.png:通用红色按钮图片。

bg_setting.png:Setting模块通用背景图片。

ic_user_head_small.png:User模块头像(小)。

selector_login_input.png:Login模块输入文本框的selector。

5. values中的id命名

1)strings

(1)命名规则

【模块名】+【控件名】+【功能名】。

(2)举例


1. <string name="loading">加载中</string>
2. <string name="button_ok">确定</string>
3. <string name="dialog_title">对话框</string>
4. <string name="main_titlebar_more">更多</string>
5. <string name="setting_title">设置页面</string>
6. <string name="search_edittext_hint">输入关键字</string>
7. <string name="login_findpassword">找回密码</string>

2)colors

(1)命名规则

【模块名或theme名】+【功能名】+【颜色编码】。

(2)举例


1. <!-- Basic colors -->
2. <color name="white">#FFFFFF</color>3. <color name="black">#000000</color>
4. <color name="red">#FF0000</color>
5. <color name="blue">#0000FF</color>
6. <color name="green">#00FF00</color>
7. <!-- Splash page -->
8. <color name="splash_yellow">#EEEE00</color>
9. <color name="splash_pink">#FFB5C5</color>
10. <!-- Feedback page -->
11. <color name="feedback_submit_black">#000000</color>

3)dimens

(1)命名规则

【模块名】+【控件名】+【描述】。

(2)举例


1. <!-- Common dimensions -->
2. <dimen name="margin_normal">16dp</dimen>3. <dimen name="margin_small">8dp</dimen>
4. <dimen name="margin_large">32dp</dimen>
5. <!-- Navigation -->
6. <dimen name="nav_drawer_width">@dimen/match_parent</dimen>7. <dimen name="nav_account_image_size">32dp</dimen>
8. <dimen name="nav_header_logo_size">36dp</dimen>

4)styles

采用大驼峰命名法。

(1)命名规则

【模块名.】+【功能名】。

(2)举例


1. <style name="ContentStyle">
2. <item name="android:layout_weight">1</item>3. <item name="android:layout_width">0dp</item>
4. </style>
5. <style name="Login.ContentStyle">
6. <item name="android:layout_weight">1</item>7. <item name="android:layout_width">0dp</item>
8. <item name="android:textSize">14sp</item>
9. <item name="android:gravity">center</item>
10. </style>

常用控件缩写表请查阅随书源码。