文章目录
-
-
- 前言
- Java 语言规范
- Android 资源文件命名与使用
-
- 【推荐】资源文件需带模块前缀。
- 【推荐】layout 文件的命名方式。
- 【推荐】 drawable 资源名称以小写单词+下划线的方式命名,根据分辨率不同存放 在不同的 drawable 目录下,建议只使用一套,例如 drawable-xhdpi。采用规则如下:``模块名_业务功能描述_控件描述_控件状态限定词``。
- 【推荐】anim 资源名称以小写单词+下划线的方式命名。采用以下规则:``模块名_逻辑名称_[方向|序号]``。
- 【推荐】 color 资源使用#AARRGGBB 格式,写入 module_colors.xml 文件中,命名格式采用以下规则:``模块名_逻辑名称_颜色``。
- 【推荐】dimen 资源以小写单词+下划线方式命名,写入 module_dimens.xml 文件中, 采用以下规则:``模块名_描述信息``。
- 【推荐】style 资源采用小写单词+下划线方式命名,写入 module_styles.xml 文件中, 采用以下规则:``父 style 名称.当前 style 名称``。
- 【推荐】string 资源文件或者文本用到字符需要全部写入 module_strings.xml 文件中, 字符串以小写单词+下划线的方式命名,采用以下规则:``模块名_逻辑名称``。
- 【推荐】Id 资源原则上以驼峰法命名,View 组件的资源 id 需要以 View 的缩写作为 前缀。
- 【推荐】常用缩写表如下:
- 【推荐】大分辨率图片(单维度超过 1000)大分辨率图片建议统一放在 xxhdpi 目录 下管理,否则将导致占用内存成倍数增加。
- Android 基本组件
-
- 【强制】Activity 间的数据通信,对于数据量比较大的,避免使用 Intent + Parcelable 的方式,可以考虑 EventBus 等替代方案,以免造成 TransactionTooLargeException。
- 【推荐】Activity#onSaveInstanceState()方法不是 Activity 生命周期方法,也不保证 一定会被调用。它是用来在 Activity 被意外销毁时保存 UI 状态的,只能用于保存临 时性数据,例如 UI 控件的属性等,不能跟数据的持久化存储混为一谈。持久化存储 应该在 Activity#onPause()/onStop()中实行。
- 【强制】Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity 检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。
- 【强制】避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确 实有需求,应改用 IntentService 或采用其他异步机制完成。
- 【强制】避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作, 应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
- 【强制】避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应 BroadcastReceiver 的 App 接收。
- 【 推 荐 】 添 加 Fragment 时 , 确 保 FragmentTransaction#commit() 在 Activity#onPostResume()或者 FragmentActivity#onResumeFragments()内调用。 不要随意使用 FragmentTransaction#commitAllowingStateLoss()来代替,任何 commitAllowingStateLoss()的使用必须经过 code review,确保无负面影响。
- 【推荐】不要在 Activity#onDestroy()内执行释放资源的工作,例如一些工作线程的 销毁和停止,因为 onDestroy()执行的时机可能较晚。可根据实际需要,在 Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。
- 【推荐】如非必须,避免使用嵌套的 Fragment。
- 【推荐】总是使用显式Intent启动或者绑定Service,且不要为服务声明IntentFilter, 保证应用的安全性。如果确实需要使用隐式调用,则可为 Service 提供 Intent Filter 并从 Intent 中排除相应的组件名称,但必须搭配使用 Intent#setPackage()方法设置 Intent 的指定包名,这样可以充分消除目标服务的不确定性。
- 【推荐】Service 需要以多线程来并发处理多个启动请求,建议使用 IntentService, 可避免各种复杂的设置。
- 【推荐】对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册 和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。
- 【推荐】当前 Activity 的 onPause 方法执行结束后才会执行下一个 Activity 的 onCreate 方法,所以在 onPause 方法中不适合做耗时较长的工作,这会影响到页面之间的跳 转效率。
- 【强制】不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
- 【推荐】使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示 Toast 时不能取消上一次 Toast 消息的情况(如果你有连续弹出 Toast 的情况,避免 使用 Toast.makeText)。
- 【强制】使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的 方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView 设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需 要为其显式设置属性(Textview 的文本为空也需要设置 setText(""),背景透明也需要 设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错 乱。
- 【强制】Activity 或者 Fragment 中动态注册 BroadCastReceiver 时,registerReceiver() 和 unregisterReceiver()要成对出现。
- UI 与布局
-
- 【强制】布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,改用 RelativeLayout,可以有效降低嵌套数。
- 【推荐】在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非 Dialog/AlertDialog,这样便于随 Activity 生命周期管理对话框/弹出浮层的生命周期。
- 【推荐】源文件统一采用 UTF-8 的形式进行编码。
- 【强制】禁止在非 ui 线程进行 view 相关操作。
- 【推荐】文本大小使用单位 dp,view 大小使用单位 dp。对于 Textview,如果在文 字大小确定的情况下推荐使用 wrap_content 布局避免出现文字显示不全的适配问 题。
- 【强制】禁止在设计布局时多次设置子 view 和父 view 中为同样的背景造成页面过 度绘制,推荐将不需要显示的布局进行及时隐藏。
- 【推荐】灵活使用布局,推荐 Merge、ViewStub 来优化布局,尽可能多的减少 UI 布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。
- 【推荐】在需要时刻刷新某一区域的组件时,建议通过以下方式避免引发全局 layout 刷新:
- 【推荐】不能在 Activity 没有完全显示时显示 PopupWindow 和 Dialog。
- 【推荐】尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会报错。
- 【强制】不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这 样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图 面。
- 进程、线程与消息通信
-
- 【强制】不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致 OOM。
- 【强制】在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。
- 【强制】新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor 或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。
- 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方 式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
- 【强制】子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在 主线程中调用。
- 【强制】不要在非 UI 线程中初始化 ViewStub,否则会返回 null。
- 【推荐】尽量减少不同 APP 之间的进程间通信及拉起行为。拉起导致占用系统资源,影响用户体验。
- 【推荐】新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。
- 【推荐】ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时 线程能被释放。
- 【推荐】禁止在多进程之间用 SharedPreferences 共享数据,虽然可以 (MODE_MULTI_PROCESS),但官方已不推荐。
- 【推荐】谨慎使用 Android 的多进程,多进程虽然能够降低主进程的内存压力,但会 遇到如下问题:
- 文件与数据库
-
- 【强制】任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。
- 【强制】当使用外部存储时,必须检查外部存储的可用性。
- 【强制】应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用 FileProvider。
- 【推荐】SharedPreference 中只能存储简单数据类型(int、boolean、String 等), 复杂数据类型建议使用文件、数据库等其他方式存储。
- 【推荐】SharedPreference 提交数据时,尽量使用 Editor#apply(),而非 Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使 用 Editor#commit()。
- 【强制】数据库 Cursor 必须确保使用完后关闭,以免内存泄漏。
- 【强制】多线程操作写入数据库时,需要使用事务,以免出现同步问题。
- 【推荐】大数据写入数据库时,请使用事务或其他能够提高 I/O 效率的机制,保证执行速度。
- 【强制】执行 SQL 语句时,应使用 SQLiteDatabase#insert()、update()、delete(), 不要使用 SQLiteDatabase#execSQL(),以免 SQL 注入风险。
- 【强制】如果 ContentProvider 管理的数据存储在 SQL 数据库中,应该避免将不受 信任的外部数据直接拼接在原始 SQL 语句中,可使用一个用于将 ? 作为可替换参 数的选择子句以及一个单独的选择参数数组,会避免 SQL 注入。
- Bitmap、Drawable 与动画
-
- 【强制】加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿。
- 【强制】在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时, 应做好图片的缓存,避免始终持有图片导致内存泄露,也避免重复创建图片,引起 性 能 问 题 。 建 议 使 用 Fresco ( https://github.com/facebook/fresco )、 Glide (https://github.com/bumptech/glide)等图片库。
- 【强制】png 图片使用 tinypng 或者类似工具压缩处理,减少包体积。
- 【推荐】应根据实际展示需要,压缩图片,而不是直接显示原图。手机屏幕比较小,直接显示原图,并不会增加视觉上的收益,但是却会耗费大量宝贵的内存。
- 【强制】使用完毕的图片,应该及时回收,释放宝贵的内存。
- 【推荐】针对不同的屏幕密度,提供对应的图片资源,使内存占用和显示效果达到 合理的平衡。如果为了节省包体积,可以在不影响 UI 效果的前提下,省略低密度图 片。
- 【强制】在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执 行的的动画。
- 【推荐】在动画或者其他异步任务结束时,应该考虑回调时刻的环境是否还支持业 务处理。例如 Activity 的 onStop()函数已经执行,且在该函数中主动释放了资源, 此时回调中如果不做判断就会空指针崩溃。
- 【推荐】使用 inBitmap 重复利用内存空间,避免重复开辟新内存。
- 【推荐】使用 ARGB_565 代替 ARGB_888,在不怎么降低视觉效果的前提下,减少 内存占用。
- 【推荐】尽量减少Bitmap(BitmapDrawable)的使用,尽量使用纯色(ColorDrawable)、 渐变色(GradientDrawable)、StateSelector(StateListDrawable)等与 Shape 结 合的形式构建绘图。
- 【推荐】谨慎使用 gif 图片,注意限制每个页面允许同时播放的 gif 图片,以及单个 gif 图片的大小。
- 【参考】大图片资源不要直接打包到 apk,可以考虑通过文件仓库远程下载,减小包 体积。
- 【推荐】根据设备性能,选择性开启复杂动画,以实现一个整体较优的性能和体验;
- 【推荐】在有强依赖 onAnimationEnd 回调的交互时,如动画播放完毕才能操作页面,onAnimationEnd 可能会因各种异常没被回调(参考: https://stackoverflow.com/questions/5474923/onanimationend-is-not-getting-calle d-onanimationstart-works-fine ), 建 议 加 上 超 时 保 护 或 通 过 postDelay 替 代onAnimationEnd。
- 【推荐】当 View Animation 执行结束时,调用 View.clearAnimation()释放相关资源。
- 安全
-
- 【强制】使用 PendingIntent 时,禁止使用空 intent,同时禁止使用隐式 Intent。
- 【强制】禁止使用常量初始化矢量参数构建 IvParameterSpec,建议 IV 通过随机方 式产生。
- 【强制】将 android:allowbackup 属性设置为 false,防止 adb backup 导出数据。
- 【强制】在实现的 HostnameVerifier 子类中,需要使用 verify 函数效验服务器主机 名的合法性,否则会导致恶意程序利用中间人攻击绕过主机名效验。
- 【强制】利用 X509TrustManager 子类中的 checkServerTrusted 函数效验服务器端 证书的合法性。
- 【强制】META-INF 目录中不能包含如.apk,.odex,.so 等敏感文件,该文件夹没有经 过签名,容易被恶意替换。
- 【强制】Receiver/Provider 不能在毫无权限控制的情况下,将 android:export 设置 为 true。
- 【参考】数据存储在 Sqlite 或者轻量级存储需要对数据进行加密,取出来的时候进 行解密。
- 【强制】阻止 webview 通过 file:schema 方式访问本地敏感数据。
- 【强制】不要广播敏感信息,只能在本应用使用 LocalBroadcast,避免被别的应用收到,或者 setPackage 做限制。
- 【强制】不要把敏感信息打印到 log 中。
- 【强制】对于内部使用的组件,显示设置组件的"android:exported"属性为 false。
- 【强制】应用发布前确保 android:debuggable 属性设置为 false。
- 【强制】使用 Intent Scheme URL 需要做过滤。
- 【强制】密钥加密存储或者经过变形处理后用于加解密运算,切勿硬编码到代码中。
- 【强制】将所需要动态加载的文件放置在 apk 内部,或应用私有目录中,如果应用 必须要把所加载的文件放置在可被其他应用读写的目录中(比如 sdcard),建议对不 可信的加载源进行完整性校验和白名单处理,以保证不被恶意代码注入。
- 【强制】除非 min API level >=17,请注意 addJavascriptInterface 的使用。
- 【强制】使用 Android 的 AES/DES/DESede 加密算法时,不要使用默认的加密模式 ECB,应显示指定使用 CBC 或 CFB 加密模式。
- 【强制】不要使用 loopback 来通信敏感信息。
- 【推荐】对于不需要使用 File 协议的应用,禁用 File 协议,显式设置 webView. getSettings().setAllowFileAccess(false),对于需要使用 File 协议的应用,禁止 File 协议调用 JavaScript,显式设置 webView.getSettings().setJavaScriptEnabled(false)。
- 【强制】AndroidAPP在HTTPS通信中,验证策略需要改成严格模式。说明:Android APP 在 HTTPS 通信中,使用 ALLOW_ALL_HOSTNAME_VERIFIER,表示允许和 所有的 HOST 建立 SSL 通信,这会存在中间人攻击的风险,最终导致敏感信息可能 会被劫持,以及其他形式的攻击。
- 【推荐】Android5.0 以后安全性要求较高的应用应该使用 window.setFlag (LayoutParam.FLAG_SECURE) 禁止录屏。
- 【推荐】zip 中不建议允许../../file 这样的路径,可能被篡改目录结构,造成攻击。 说 明:当 zip 压缩包中允许存在"../"的字符串,攻击者可以利用多个"../"在解压时改变 zip 文件存放的位置,当文件已经存在是就会进行覆盖,如果覆盖掉的文件是 so、 dex 或者 odex 文件,就有可能造成严重的安全问题。
- 【强制】开放的 activity/service/receiver 等需要对传入的 intent 做合法性校验。
- 【推荐】加密算法:使用不安全的 Hash 算法(MD5/SHA-1)加密信息,存在被破解的风险,建议使用 SHA-256 等安全性更高的 Hash 算法。
- 【推荐】Android WebView 组件加载网页发生证书认证错误时,采用默认的处理方法 handler.cancel(),停止加载问题页面。
- 【推荐】直接传递命令字或者间接处理有敏感信息或操作时,避免使用 socket 实现, 使用能够控制权限校验身份的方式通讯。
- 其他
-
前言
阿里Android编码规范下载地址:https://yq.aliyun.com/attachment/download/?id=5259。
优快云本地下载地址:https://download.youkuaiyun.com/download/zhiyuan411/86732286。
目标是:
- 防患未然,提升质量意识,降低故障率和维护成本;
- 标准统一,提升协作效率;
- 追求卓越的工匠精神,打磨精品代码。
根据约束力强弱, 规约依次分为强制、推荐、参考三大类:
- 【强制】必须遵守,违反本约定或将会引起严重的后果;
- 【推荐】尽量遵守,长期遵守有助于系统稳定性和合作效率的提升;
- 【参考】充分理解,技术意识的引导,是个人学习、团队沟通、项目合作的方 向。
Java 语言规范
参见: