安卓开发博客Android收藏集

Android代码规范

2018-07-24  本文已影响4人  不会敲代码的好代码

一、Android组件

  1. 通信,对于数据量比较大的,避免使用 Intent + Parcelable的方式,可以考虑 EventBus 等替代方案,以免造成 TransactionTooLargeException。
  2. Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。
  3. 避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成。
  4. 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
  5. 避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应BroadcastReceiver 的 App 接收。
  6. 不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
  7. 使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需要为其显式设置属性(Textview 的文本为空也需要设置 setText(""),背景透明也需要设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错乱。
  8. Activity或者Fragment中动态注册BroadCastReceiver时,registerReceiver()和 unregisterReceiver()要成对出现。

二、UI布局

  1. 布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,改用 RelativeLayout,可以有效降低嵌套数。节点所处位置越深,套嵌带来的 measure 越多,计算就会越费时。
  2. 禁止在非 ui 线程进行 view 相关操作。
  3. 禁止在设计布局时多次设置子 view 和父 view 中为同样的背景造成页面过度绘制,推荐将不需要显示的布局进行及时隐藏。
  4. 不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。

三、进程、线程和消息通信

  1. 不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致 OOM。
  2. 在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。
  3. 新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。
  4. 子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。
  5. 不要在非 UI 线程中初始化 ViewStub,否则会返回 null。

四、文件与数据库

  1. 任何时候都不要硬编码文件路径,这不仅存在安全隐患,也让 app 更容易出现适配问题。
  2. 应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用FileProvider。
  3. SharedPreference 提 交 数 据 时 , 尽 量 使 用 Editor#apply() , 而 非Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使用 Editor#commit()。SharedPreference 相关修改使用 apply 方法进行提交会先写入内存,然后异步写入磁盘,commit 方法是直接写入磁盘。如果频繁操作的话 apply 的性能会优于 commit,apply 会将最后修改内容写入磁盘。但是如果希望立刻获取存储操作的结果,并据此做相应的其他操作,应当使用 commit。
  4. 数据库 Cursor 必须确保使用完后关闭,以免内存泄漏。
  5. 多线程操作写入数据库时,需要使用事务,以免出现同步问题。
    说明:
    Android 的通过 SQLiteOpenHelper 获取数据库 SQLiteDatabase 实例,Helper 中会自动缓存已经打开的 SQLiteDatabase 实例,单个 App 中应使用 SQLiteOpenHelper的单例模式确保数据库连接唯一。由于SQLite 自身是数据库级锁,单个数据库操作是保证线程安全的(不能同时写入),transaction 时一次原子操作,因此处于事务中的操作是线程安全的。若同时打开多个数据库连接,并通过多线程写入数据库,会导致数据库异常,提示数据库已被锁住。
  6. 执行 SQL 语句时,应使用 SQLiteDatabase#insert()、update()、delete(),不要使用 SQLiteDatabase#execSQL(),以免 SQL 注入风险。
  7. 如果 ContentProvider 管理的数据存储在 SQL 数据库中,应该避免将不受信任的外部数据直接拼接在原始 SQL 语句中,可使用一个用于将 ? 作为可替换参数的选择子句以及一个单独的选择参数数组,会避免 SQL 注入。

五、Bitmap、Drawable 与动画

  1. 加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿。
  2. 在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时,应做好图片的缓存,避免始终持有图片导致内存泄露,也避免重复创建图片,引起性能问题 。
  3. png 图片使用 tinypng 或者类似工具压缩处理,减少包体积。
  4. 使用完毕的图片,应该及时回收,释放宝贵的内存。
  5. 在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执行的的动画。

六、安全

  1. 使用 PendingIntent 时,禁止使用空 intent,同时禁止使用隐式 Intent
    说明:
    1)使用 PendingIntent 时,使用了空 Intent,会导致恶意用户劫持修改 Intent 的内容。禁止使用一个空 Intent 去构造 PendingIntent,构造 PendingIntent 的 Intent一定要设置 ComponentName 或者 action。
    2)PendingIntent 可以让其他 APP 中的代码像是运行自己 APP 中。PendingIntent的intent接收方在使用该intent时与发送方有相同的权限。在使用PendingIntent时,PendingIntent 中包装的 intent 如果是隐式的 Intent,容易遭到劫持,导致信息泄露。
  2. 将 android:allowbackup 属性设置为 false,防止 adb backup 导出数据。
    说明:
    在 AndroidManifest.xml 文件中为了方便对程序数据的备份和恢复在 Android API level 8 以后增加了 android:allowBackup 属性值。默认情况下这个属性值为 true,故当 allowBackup 标志值为 true 时,即可通过 adb backup 和 adb restore 来备份和恢复应用程序数据。
  3. 利用 X509TrustManager 子类中的 checkServerTrusted 函数效验服务器端证书的合法性。
  4. META-INF 目录中不能包含如.apk,.odex,.so 等敏感文件,该文件夹没有经过签名,容易被恶意替换。
  5. Receiver/Provider 不能在毫无权限控制的情况下,将 android:export 设置为 true。
  6. 阻止 webview 通过 file:schema 方式访问本地敏感数据。
  7. 不要广播敏感信息,只能在本应用使用 LocalBroadcast,避免被别的应用收到,或者 setPackage 做限制。
  8. 不要把敏感信息打印到 log 中。
  9. 应用发布前确保 android:debuggable 属性设置为 false。
  10. 使用 Intent Scheme URL 需要做过滤。
  11. 密钥加密存储或者经过变形处理后用于加解密运算,切勿硬编码到代码中。
  12. 使用 Android 的 AES/DES/DESede 加密算法时,不要使用默认的加密模式ECB,应显示指定使用 CBC 或 CFB 加密模式。
    说明:
    加密模式 ECB、CBC、CFB、OFB 等,其中 ECB 的安全性较弱,会使相同的铭文在不同的时候产生相同的密文,容易遇到字典攻击,建议使用 CBC 或 CFB 模式。
    1)ECB:Electronic codebook,电子密码本模式
    2)CBC:Cipher-block chaining,密码分组链接模式
    3)CFB:Cipher feedback,密文反馈模式
    4)OFB:Output feedback,输出反馈模式
  13. 开放的 activity/service/receiver 等需要对传入的 intent 做合法性校验。
上一篇下一篇

猜你喜欢

热点阅读