Android Developer

寺库android客户端编码约定

参数命名

  • 如果不是成员变量,不要用m作为前缀,m是member的意思。

按照JAVA中变量的定义方式定义.首字母小写,驼峰命名法. 例如: 用户名: XML注释 如果当前layout或者资源要被多处调用,或者为公共布局文件,需要在XML里面写清楚注释,注释的规则如下 使用结尾,同时保证注释内容在一个组件或者布局的头部,不允许在组件或者布局内进行注释(这样XML无法编译通过) 例子

异常处理

  • 如果使用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必须要添加注释。