参数命名
- 如果不是成员变量,不要用m作为前缀,m是member的意思。
按照JAVA中变量的定义方式定义.首字母小写,驼峰命名法.
例如:
异常处理
- 如果使用try catch捕获了异常,这里约定要执行Throwable(及其子类)的printStackTrace,这样能够通过日志抓取就可以了解到应用执行的轨迹。
1.不要忽视异常处理
如果像下面的代码这样,对catch后的异常作空处理,就像埋下地雷一样让人感觉到毛骨悚然: 错误的做法:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
}
}
正确的做法: 在方法声明时抛出异常,由客户程序员去负责消化这个异常。
void setServerPort(String value) throws NumberFormatException {
serverPort = Integer.parseInt(value);
}
2.不要偷懒而捕捉一般异常
下面代码一概捕捉Exception异常,大小通吃是不对的,这样会让你在错误出现时难以定位到错误原因,一般异常无法用统一方法进行异常处理。 错误的做法:
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!
}
在Exception中请使用android的Log来打印一些异常信息,不要使用Java的打印堆栈,这样能够在Logcat里面看到错误。
Log信息书写规范
Log要加入开关控制,以便在发布重要版本和产品版本时能够选择性关闭.推荐写一个通用的LOG输出类来对系统的LOG进行简单的封装。 要定义明确TAG,TAG格式如下:
private static final String TAG = “packname_modulename” (包名_模块名)
这样可以方便在调试过程中通过adb logcat –s 来选择打印信息 示例:
private static final boolean DEBUG_SETTINGS = true;
private static final String TAG = “com.androd.setting_wifi”;
if(DEBUG_SETTINGS)
Log.i( TAG ,“debug settings");
1.在每一个.java文件内,必须只有一个TAG,不能在一个java文件内定义多个TAG,保证同一个文件输出统一的TAG Log,同时推荐使用于Java文件同名的TAG名称,如果有重复的现象出现,建议添加包名作为区分.文件内所有输出的Log必须使用TAG,不允许自己在Log内写入TAG. 例子
Log.d(TAG,”Something to out put ”); //正确写法
Log.d(“MyTag”,”Something to out put ”); //错误写法
2.在异常的地方要写入Log信息,保证出现异常的时候能够在Log内看到有效的信息,保证调试的顺利进行
3.在switch的未处理的分支(default)内需要输出Log,将当前的case值输出到控制台
避免内存泄露
原则1 及时回收Bitmap资源
对于在代码中创建出来的Bitmap资源,一定要在适当的时候通过Bitmap.recycle()予以销毁,系统不会对通过Bitmap.createBitmap方式创建出来的Bitmap进行回收。合理的时候比如在Activity.onDestroy()中销毁Bitmap. 示例: 创建:
Bitmap mybitmap = Bitmap.createBitmap();
回收:
mybitmap.recycle();
原则2 无论何时register注册的响应钩子,一定要有unRegister的时候,否则该引用不能被系统正确回收。同时建议注册和反注册要分别写在onResume,和onPause中,这样可以有效防止因为页面崩溃导致的泄漏
示例:
public void onCreate() {
setCallback(mycallback);
RegisterReceiver(myReceiver);
}
public void onStop() {
setCallback(null);
unRegisterFilter(myReceiver);
}
Regiser注册的内容很多,请务必仔细,如contentObserver, Cursor, CallBack函数都是需要清理的对象。
原则3 在使用Adapter的时候,要尽量使用convertView缓存引用,以便节省内存空间。 示例:
View Adapter.getView(View converView, int pos) {
View v;
if (convertView != null) //如果converView存在,那么使用converView来作为创建出的View引用。
v = convertView;
else //如果convertView不存在,则创建新的View引用。
v = makeNewView();
v.setData();//给View引用设置数据
return v;
}
避免出现系统超时无响应
在使用过程中,我们有时候会遇到界面无响应,弹出对话框询问是关闭进程还是继续等待,发生该异常的原因是应用主线程在某处阻塞,导致新的系统消息(如广播Intent, Key事件, Touch事件)不能正常处理,系统端迟迟收不到应用返回的消息已处理事件,从而判定应用无响应,弹出提示对话框。同时,长时间的阻塞主线程可能会导致WindowManagerService不能正确处理窗口切换刷新,引起打开/关闭Activity时出现刷新不正常。
发生异常时常见的Log有:
Activitiy Idle timeout …
Activity Launch timeout
Service execute timeout
Key dispatch timeout
Broadcast Receiver Intent *** timeout
避免这个问题有以下几个原则。
原则1
需要时间很长的操作,须要单独启动新的线程执行。
例如:
搜索网络,Wifi
网络访问
加载/卸载Sd卡
大量读写数据库
读写较大文件(比如大尺寸的图片)
通常与底层数据读取相关的函数需要重点关注。启动新线程要使用Thread.start()函数,而不是用Thread.run()函数。使用线程一定要注意synchronized同步以及资源回收
原则2
对于结构不易另外开新线程的代码, 或者调用Binder与其它能够联系的代码 , 应该尽量避免在系统回调函数中直接运行,要通过sendMessage来异步调用,这样可以保证系统能够及时从应用获得消息处理完毕的事件。
例如:
startActivity() 打开Activity
startService() 打开Service
sendBroadcast() 发Intent广播
showDialog() 显示对话框
耗时长的事件可能较多,需要大家实际分析,比如获取当前网络,硬件,电话等底层状态都可能会导致阻塞 需要避免出现代码示例:
Public void onCreate(){
sendBroadcast(testIntent);
}
在onCreate回调函数中发送广播以及显示对话框,有可能会造成系统端阻塞
正确示例:
public int TEST_MSG = 0;
public Handler myHandler = new Handler()
public void handleMessage(Message msg) {
switch (msg.what)
{
case TEST_MSG:
sendBroadCast(myintent);
break;
}
}
public void onCreate(){
myHandler.sendMessage(myHandler.obtainMessage(TEST_MSG));
}
通过发送Message的方式来异步调用。 请注意: 发送Message只是将要执行的操作放到onCreate()回调函数之外去操作,并不是启动新线程进行,如果需要时间过长,同样可能引发阻塞。 目前系统中判定,广播超时和按键超时时间是10s,因此,如果是可能超过数秒的操作,应该启动新线程,否则就应该使用Message方式异步调用。
原则3
某些代码调用应该坚持少访问数据库,少读取文件,少访问网络的设计原则 例如:
Settings.System.getInt() 操作会读取数据库 ,可以通过使用变量或者System.Properties的方式来替代。
原则4
尽量避免使用onConfigurationChanged的方式来实现Activity横竖屏切换。 使用onConfigurationChanged的方式能够在不重新创建Activity的情况下实现横竖屏切换,但是其缺点有:
(1) 若该函数内执行操作过多会导致系统闪屏
(2) 内存不能及时回收,如果代码处理不当容易引起内存泄露
(3) 无法实现横竖屏切换时layout的自动切换
在使用onConfigurationChanged的时候,务必重载super.onConfigurationChanged()
原则5
尽量避免使用System.exit(0)的方式来退出应用,尤其需要注意当有其它并发线程的时候,System.exit(0)可能会带来一系列风险。 使用System.exit(0) . Process.killProcess会直接杀掉当前进程,而android中默认是不会关闭进程的,在杀掉当前进程的时候需要考虑并发线程的状态,例如如果并发线程当前正在读取文件,操作数据库,跨进程访问,这时关闭进程就会导致一系列问题甚至引起系统崩溃。
布局
布局文件名称的定义必须为小写字母,否者无法生成R类,尽量不要用缩写.以表达清楚该文件用途为本,通常情况下用下划线连接各语义单词,例如 dialog_title_icons.xml 或者list_menu_item_checkbox.xml. 控件ID的定义,ID的定义一律为小写,例如:一用户名 TextView 可以定义为:@+id/username_view .以“名词_控件名称”这种形式定义. String类的name定义
代码注释规范
代码注释是架起程序设计者与阅读者之间通信的桥梁,能最大限度的提高团队开发合作效率,也是代码便于维护的重要环节之一。
项目中遇到的问题:
-
一个类的代码量上千行,没有代码注释。
-
静态常量/变量的命名不规范,又没有代码注释。
-
请求接口没有注释。
-
复杂XML一句注释都没有。
-
…
如上出现的问题相信很多人都遇到过,没有一些重要的注释会严重降低开发者的效率,要花很长时间来吃透代码,既浪费时间又影响代码可读性。
所以我们制定了如下的代码注释规范:
-
典型算法必须有注释。
-
在代码不明晰处必须有注释。
-
在代码修改处加上修改标识注释。
-
在循环和逻辑分支组成的代码中加注释。
-
为他人提供的接口必须加详细注释。
-
复杂xml必须要添加注释。