ANDROID 开发规范总结
基本原则
工欲善其事,必先利其器
充分利用好工具,让电脑代替人脑
最高境界是不写任何代码
和产品人员充分讨论,仔细评估待实现的功能,明确方案,不做无用功(最好能把需求砍掉J)
为质量负责
提交代码前仔细检查,找同事帮忙review
如果迫不得已,挖坑前做好标记(TODO)
工具和开发环境
开发推荐使用eclipse,或者类eclipse环境
配置好Android Formatter
配置好Save Actions
Formatter配置
Eclipse -> Window -> Preferences
Import 导入相应的formatter.xml文件
Save Actions配置
eclipse -> Window -> Preferences
配置成如上的形式就可以了。
UI编码规范
不要阻塞UI线程
1、UI线程内不能做耗时操作,如文件读写、数据库操作、逻辑运算等,建议每次调用耗时不超过10ms,如果超过,建议在工作线程内完成。
2、使用trace view查找耗时方法。
3、使用StrictMode监测耗时操作。
优化高频率运行的代码
1、不频繁进行findViewById、getString…等查找资源的操作, 应使用临时对象缓存。
2、避免频繁创建对象
–自定义View不能每帧刷新都去创建新的Paint、Rect、Matrix等对象,应使用临时对象缓存,一次性创建并初始化,每次直接使用。
–当需要重复使用Bitmap时,不要频繁进行decode,而应将其缓存在cache中。(注:安卓3.0以下可使用软引用cache,3.0以上使用LRU cache并需自己做好内存控制。 为了统一和适配,建议使用后者”)。
避免过度刷新
主要是item很多的ListView的过度刷新
1、 不要频繁调用Adapter的notifyDataSetChanged方法,只更新需要被更新的行。
常见的场景:后台频繁更新数据,界面接收到回调后直接notifyDataSetChanged。正确的方法:判断后台数据对应的行是否可见,然后刷新该View。
2、listview滑动的过程中少调用notifyDataSetChanged。
3、Adapter需使用复用机制,不能每次getView都去重新inflate, 应尽量利用convertView 和 ViewHolder来实现复用机制。
布局扁平化
1、 多使用merge、ViewStub标签。
2、使用RelativeLayout代替多级Linearlayout。
3、使用hierarchy view排查布局问题。
不使用大尺寸图片
1、使用BitmapFactory类的decode函数生成bitmap时,调整采样间隔和缩放尺寸,进行预缩放处理
2、避免使用多套分辨率图片
为了保证不同分辨率手机ui效果,可能会在hdpi、xhdpi等目录下各保持一份图片,这样做会增加apk体积,尽量只放一套图片,然后指定View的高宽,在不同分辨率下定义不同的dimen。
正确使用inflate方法
不正确的使用inflate(Contextcontext, int resource, ViewGroup root)方法导致View Hierarchy多嵌套了一层,会导致View效率低下。
错误的作法:
正确的做法:
解决办法:在inflate第三个参数给定root的时候,应该在xml文件中用merge标签消除嵌套,并且在代码中设置相关属性(xml文件中使用merge标签,对这一标签的任何属性都将失效,包括id,可以看作没有这一层)。
使用ColorFilter节省图片资源
一个按钮拥有多种状态,为满足这些状态使用了不同的切图
尽可能的使用ColorFilter,使用ColorFilter可节省50%内存使用
界面元素尽量少且简单
如果一个Activity展示的元素过多,肯定会影响性能,可以考虑下面的方法:
1、把业务逻辑分拆到不同的界面。
2、使用Fragment展示不同的界面。
3、使用自定义Layout展示不同的界面,不同的情况切换不同的Layout。
UI逻辑和业务逻辑分离
如果activity逻辑很复杂,建议将UI和业务逻辑放到单独的类实现,用Message传递消息,
Adapter数据变化问题
如果在非ui线程修改Adapter内容(增加item),会抛出下面的异常:
java.lang.IllegalStateException: Thecontent of the adapter has changed but ListView did not receive a notification.Make sure the content of your adapter is not modified from a background thread,but only from the UI thread
修改方法是在UI线程中修改,可以通过Handler解决数据传递问题。
使用include复用layout
Include可以减少重复资源,布局文件更清晰。
设置窗口背景为null
<item name="android:windowBackground">@null</item>
可以省去window背景的绘制,提高界面效率
实践经验
修复BUG时,避免简单粗暴
修复BUG时,要尽量找到问题的根本原因。不要直接加上try/catch完事。
避免Context对象使用强制类型转换
避免使用Context转换为Activity,禁止使用Context转换为Application。
持有Context对象
尽量用context.getApplicationContext代替
谁申请谁释放原则
Receiver的注册和注销,包括Android的和LocalBroadcastManager
Service的bind和unbind
一定要保证成对出现,否则导致内存泄漏
Fragment的细节
Fragment的onCreateView/onDestroy/handleMessage,要判断Activity是否为空,是否finish
Fragment继承注意事项
继承Fragment的子类,其构造函数必须是无参数的,需要的Activity父对象可以通过onAttach(Activity)来传递。
public Activity mContext;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mContext = activity;
}
否则会报告如下错误:
Caused by:android.support.v4.app.Fragment$InstantiationException: Unable to instantiatefragment alj: make sure class name exists, is public, and has an emptyconstructor that is public
at android.support.v4.app.Fragment.instantiate(Fragment.java:395) com.qihoo360.mobilesafe.ui.fragment.settings.SettingsView -> alj
at android.support.v4.app.FragmentState.instantiate(Fragment.java:96)
atandroid.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1726)
at android.suppo
Dialog的show/dismiss
需要判断Activity是否finish
AsyncTask的onPost
需要判断Activity是否finish
Android的Receiver上下文
Android的Receiver上下文是限制上下文,不能用其Context去bindService操作
Handler/Runnable内存泄漏
要小心Handler/Runnable对Activity等的长期持有
AsyncTask内存泄漏
要小心AsyncTask对Activity等的长期持有
Toast使用
Toast最好在UI线程中启动,否则可能会报错:
04-17 19:04:29.424: E/CrashHandler(11689):Crash Log BEGIN
04-17 19:04:29.424: E/CrashHandler(11689):java.lang.RuntimeException: Can't create handler inside thread that has notcalled Looper.prepare()
04-17 19:04:29.424: E/CrashHandler(11689):at android.os.Handler.<init>(Handler.java:121)
04-17 19:04:29.424: E/CrashHandler(11689):at android.widget.Toast$TN.<init>(Toast.java:317)
04-17 19:04:29.424: E/CrashHandler(11689):at android.widget.Toast.<init>(Toast.java:91)
明文字符串
尽量不要在传输中直接传输明文字符串。