开发规范:《阿里巴巴Android开发手册》之初理解
今天一早就看见了《阿里巴巴Android开发手册》开放下载的推送。该开发规范在阿里内部经过了长期的修缮,现已总结成册,向所有移动开发者、技术爱好者开放,希望帮助开发者码出高效、码出质量,提升系统的质量、协作的高效性。粗略翻阅一遍后,总结出部分规范。日后再当细读。下载地址:《阿里巴巴Android开发手册》下载
前言
《阿里巴巴 Android 开发手册》(以下简称《手册》)是阿里各大 Android 开发团队的集体智慧结晶和经验总结,将多个 App 长期开发迭代和优化经验系统地整理成册,以指导 Android 开发者更加高效、高质量地进行 App 开发。共同遵循同一开发规范,既是高效合作的基础,也是深度创新的开始。《手册》遵循《阿里巴巴 Java 开发手册》手册下载地址:https://yq.aliyun.com/articles/693 。以java为开发语言,制定相应规范,对kotlin等并未涉及。目录结构如下:
《阿里巴巴Android开发手册》目录Android 资源文件命名与使用
《手册》中推荐资源命名时增加模块前缀,以此区分,方便查找。drawable 资源名称以小写单词+下划线的方式命名,根据分辨率不同存放在不同的 drawable 目录下,建议只使用一套,例如 drawable-xhdpi。大分辨率图片(单维度超过 1000)大分辨率图片建议统一放在 xxhdpi 目录下管理,否则将导致占用内存成倍数增加。
Android 基本组件
Android 基本组件指 Activity、Fragment、Service、BroadcastReceiver、ContentProvider 等。《手册》进行了17点讲解,大致可以从3个角度来进行理解。
从代码严谨度来考虑:
以下几点都为了减少bug,因此都为强制:
- Activity 间的数据通信,数据量较大时,避免使用 Intent + Parcelable的方式,可以考虑 EventBus 等替代方案,以免造成 TransactionTooLargeException。
- Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。
- 避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成。
- 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
- 不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
- 使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需要为其显式设置属性(Textview 的文本为空也需要设置 setText(""),背景透明也需要设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错乱。
- Activity或者 Fragment 中动态注册BroadCastReceiver 时,registerReceiver()和 unregisterReceiver()要成对出现。
说明:如果 registerReceiver()和 unregisterReceiver()不成对出现,则可能导致已经注册的receiver 没有在合适的时机注销,导致内存泄漏,占用内存空间,加重 SystemService负担。部分华为的机型会对 receiver 进行资源管控,单个应用注册过多 receiver 会触发管控模块抛出异常,应用直接崩溃。
从性能考虑:
- 如非必须,避免使用嵌套的 Fragment。
- 当前Activity的onPause方法执行结束后才会执行下一个Activity的onCreate方法,所以在 onPause 方法中不适合做耗时较长的工作,这会影响到页面之间的跳转效率。
- 对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。说明:对于使用 Context#sendBroadcast()等方法发送全局广播的代码进行提示。如果该广播仅用于应用内,则可以使用 LocalBroadcastManager 来避免广播泄漏以及广播被拦截等安全问题,同时相对全局广播本地广播的更高效。
- Service 需要以多线程来并发处理多个启动请求,建议使用 IntentService,可避免各种复杂的设置。说明:Service 组件一般运行主线程,应当避免耗时操作,如果有耗时操作应该在 Worker线程执行。 可以使用 IntentService 执行后台任务。
- 总是使用显式 Intent 启动或者绑定 Service,且不要为服务声明 Intent Filter,保证应用的安全性。如果确实需要使用隐式调用,则可为 Service 提供 Intent Filter并从 Intent 中排除相应的组件名称,但必须搭配使用 Intent#setPackage()方法设置Intent 的指定包名,这样可以充分消除目标服务的不确定性。
- 不要在 Activity#onDestroy()内执行释放资源的工作,例如一些工作线程的销毁和停止,因为 onDestroy()执行的时机可能较晚。可根据实际需要,在Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。
- 添 加 Fragment 时 , 确 保 FragmentTransaction#commit() 在Activity#onPostResume()或者 FragmentActivity#onResumeFragments()内调用。不要随意使用 FragmentTransaction#commitAllowingStateLoss()来代替,任何commitAllowingStateLoss()的使用必须经过 code review,确保无负面影响。
- Activity#onSaveInstanceState()方法不是 Activity 生命周期方法,也不保证一定会被调用。它是用来在 Activity 被意外销毁时保存 UI 状态的,只能用于保存临时性数据,例如 UI 控件的属性等,不能跟数据的持久化存储混为一谈。持久化存储应该在 Activity#onPause()/onStop()中实行。
从用户体验考虑:
- 使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示Toast 时不能取消上一次 Toast 消息的情况(如果你有连续弹出 Toast 的情况,避免使用 Toast.makeText)
UI 与布局:
这部分内容主要是一些基础规范,比如灵活使用布局,推荐 Merge、ViewStub 来优化布局,尽可能多的减少 UI
布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。