Android 项目优化(七):阿里巴巴Android开发手册整理总结

本来之前觉得Android项目优化系列的文章基本整理完毕了,但是近期看了一下《阿里Android开发手册》有了很多收获,想再整理一篇,下面就开始吧。

先在这里列一下之前整理的文章及链接:

Android 项目优化(一):项目代码规范优化

Android 项目优化(二):启动页面优化

Android 项目优化(三):MultiDex 优化

Android 项目优化(四):内存优化

Android 项目优化(五):应用启动优化

 
下面是《阿里巴巴Android开发手册》为我们提供的开发建议。

一、Android 基本组件开发规范

1. Activity 开发

必须要遵守的开发规范如下:

a). Activity 间数据通信,对于数据量比较大的,避免使用Intent + Parcelable的方式,可以考虑使用EventBus等替代方案,以免造成TransactionTooLargeException异常。

b). Activity 间通过隐式的Intent跳转,在Intent发出去之前必须使用resolveActivity检查,避免找不到合适的调用组件,造成ActivityNotFoundException异常。

c). Activity 动态注册BroadCastReceiver时,registerReceiver和unregisterReceiver方法要成对出现,且生命周期对应。(否则会导致内存泄漏,部分华为机型对receiver进行资源管控,单个应用注册过多receiver会触发管控模块抛出异常,可能会导致应用崩溃。)

建议的遵守的开发规范如下:

a). 不要在Activity的onDestroy()内执行释放资源的工作,例如一些工作线程的销毁和停止。因为onDestroy执行的时机可能较晚了,可以根据时机需要在Activity的onPause或onStop方法中结合isFinishing来判断执行相应的逻辑。

b). 当前Activity的onPause方法执行结束后才会创建(onCreate)或恢复(onRestart)别的Activity,所以在onPause方法中不适合做耗时较长的操作,耗时较长的操作会影响页面之间的跳转效率。

c). Activity的onSaveInstanceState方法不是Activity生命周期方法,也不保证一定会被调用。它是用来在Activity被意外销毁时保存UI状态的,只能用于保存临时数据,例如UI控件的属性,不能用于数据持久化的存储控制。持久化存储应该在Activity的onPause/onStop中实行。

2. Service 开发

必须要遵守的开发规范如下:

a). 避免在Service的onStartCommand/onBind方法中执行耗时操作,如果确实有需求,应改为IntentService或者采用其他异步机制完成。

建议的遵守的开发规范如下:

a). Service需要以多线程并发处理多个启动请求,建议使用IntentService,可避免各种复杂的配置。

b). 建议总是使用显式的Intent启动或者绑定Service,且不要为Service声明Intent Filter,保证应用的安全性。如需要隐式调用,建议设置Intent的指定包名,这样可以充分消除目标Service的不确定性。

3. BroadCastReceiver开发

必须要遵守的开发规范如下:

a). 避免在BroadCastReceiver的onReceive方法中执行耗时操作,如果有耗时工作,应该创建IntentService完成,而不应该在BroadCastReceiver内创建子线程去做。

b). 避免使用隐式的Intent广播敏感信息,信息可能被其他注册了对应的BroadCastReceiver的App接收。如果广播仅限于应用内,可使用LocalBroadcastManager的sendBroadcast实现,避免敏感信息外泄和Intent拦截的风险。

建议的遵守的开发规范如下:

a). 对于只用于应用内的广播,优先使用LocalBroadcastManager来注册和发送,LocalBroadcastManager安全性更好,能避免敏感信息外泄和Intent拦截的风险,同时拥有更高的运行效率。

二、UI 与 布局开发规范

必须要遵守的开发规范如下:

a). 布局中不得不使用ViewGroup多重嵌套时,不要使用LinearLayout嵌套,改用RelativeLayout,可以降低嵌套层数。

说明:Android 应用页面的任何一个View都需要经过measure、layout、draw三个步骤才能被正确的渲染。嵌套层级越多,带来的measure次数越多,计算就会越费时。

b). 不要在非UI线程进行View相关的操作。

c). 不能用ScrollView包裹ListView/GridView/ExpandableListView,因为这样会把ListView的所有Item都加载到内存中,需要消耗巨大的内存和CPU去绘制画面。这里推荐使用NestedScrollView。

d). 在使用Adapter的时候,如果你使用了ViewHolder做缓存,在getView()的方法中,无论这项convertView的每个子控件是否需要设置属性,都要显式的设置属性(包括文本内容、背景色及其他属性),否则在滑动中,因为adapter item复用的原因,会出现内容的显示错乱。

建议的遵守的开发规范如下:

a). 在Activity中显示对话框或弹出浮层时,尽量使用DialogFragment,而非Dialog/AlertDialog,这样便于随Activity生命周期管理对话框/弹出浮层的生命周期。

b). 推荐文本大小使用:dp单位。推荐View大小使用:dp单位。因为:sp是Android早期推荐使用的,但sp即受屏幕密度影响又受到系统字体设置影响,dp相对能保证UI的一致性。

c). 尽量避免在Activity没有完全显示时显示PopupWindow和Dialog。

d). 尽量不要用AnimationDrawable实现帧动画(尤其图片多的时候),它在初始化时会将所有图片加载到内存,非常消耗资源(低端机可能直接OOM),且不能释放,释放后下次加载会报错。

三、进程、线程与消息通信开发规范

必须要遵守的开发规范如下:

a). 不要通过Intent在Android基础组件之间传递大数据,否则可能会导致OOM。

b). 在Application的业务初始化代码加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。

c). 新建线程时,必须通过线程池提供(AsyncTask或者ThreadPoolExecutor或者其他形式的线程池),不允许在应用中自行创建线程。

说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致内存消耗完或者过度切换的问题。另外,创建匿名线程不便于后续的资源使用的分析,对性能分析会造成困扰。

d). 线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的方式能够让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

e). 子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。

建议的遵守的开发规范如下:

a). 尽量减少不同App之间的进程通信及拉起行为。拉起会导致占用系统资源,影响用户体验。

b). 新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。

c). 使用线程池是,在业务满足的情况下尽量设置线程的存活时间(setKeepAliveTime),确保线程空闲时能够被释放。

d). 尽量避免在多进程之间用SharePreferences共享数据,虽然可以通过设置MODE_MULTI_PROCESS来实现,但是这种方式官方已经不推荐使用了。

e). 谨慎使用Android的多进程,虽然多进程能降低主进程的压力,但是需要注意以下问题:

  • 首次进入新启动进程的页面会有延迟现象(可能黑屏or白屏几秒)。
  • 应用内多进程时,Application实例化多次,需要考虑各个模块是否需要在所有进程中初始化。

另外,使用多进程还会造成如下几方面的问题:

(1)静态成员和单例模式完全失效

(2)线程同步机制完全失效

(3)SharedPreference 的可靠性下降

(4)Application 会多次创建

(1)和(2)的原因是Android会为每一个进程分配一个独立的虚拟机。(3)是因为SharedPreferences底层是通过读/写XML文件来实现的,并发读写显然很可能出现问题。(4)是大家基本都知道的问题,这里就不多赘述了。

四、文件与数据库开发规范

必须要遵守的开发规范如下:

a). 任何时候都不要硬编码文件路径,请使用Android文件系统API访问(硬编码存在机型兼容问题)。

b). 当使用外部存储时,必须检查外部存储的可用性。

c). 应用间共享文件时,不要通过放宽文件系统的权限去实现,而是应该使用FileProvier。

d). 数据库Cursor必须确保使用完后关闭,以避免内存泄漏。

e). 多线程写入数据库时,需要使用事务,以免出现同步问题。

f). 执行SQL时,应该使用SQLiteDataBase的insert、update、delete方法,不要使用execSQL方法,以免SQL注入风险。

g). 如果ContentProvider管理的数据存储在SQL数据库中,应该避免将不受信任的外部数据直接拼接在原始SQL语句中。

建议的遵守的开发规范如下:

a). SharePreference中只能存储简单数据类型(int、boolean、String等),复杂数据类型建议使用文件、数据库等其他存储方式。

b). SharePreference提交数据时,尽量使用apply方法。除非需要确定提交结果,并据此执行后续操作时,才使用commit方法。

c). 将大数据写入数据库时,请使用事务或者其他能提高I/O效率的机制,保证执行速度。

五、Bitmap、Drawable与动画

必须要遵守的开发规范如下:

a). 加载大图或者一次性加载多张图的时候,应该在异步线程中进行。图片的加载,涉及IO操作,以及CPU密集操作,很可能引起卡顿。

b). 在ListView、ViewPager、RecyclerView、GridView等组件中使用图片时,应做好图片的缓存,避免使用持有图片导致内存溢出,也要避免重复创建图片,引起性能问题。推荐使用Fresco、Glide等图片加载库。

c). 在Activity的onPause方法或onStop方法中,关闭当前Activity正在执行的动画。

建议的遵守的开发规范如下:

a). 推荐根据展示实际需要,压缩图片,而不是直接展示原图,这样能提高App的性能。

b). 使用完毕的图片,应及时回收,释放宝贵的内存。(2.3.3及以下版本需要调用recycle方法,2.3.3以上GC会自动管理不需要调用recycle方法)

c). 在动画或者其他异步任务结束时,应考虑回调时刻的环境是否还支持业务处理,并增加相关的空指针等判断逻辑。

d). 谨慎使用Gif,注意限制每个页面同时允许播放的gif图片数量,以及单个gif图片的大小。

e). 根据设备性能,选择性的开启复杂动画,以实现一个整体较优的性能和体验。

六、安全

必须要遵守的开发规范如下:

a). 将android:allowbackup属性必须设置为false,防止应用数据被导出。

说明:android:allowbackup 是Android提供的adb调试功能,如果设置为true,可以导出应用数据并在任意设备上恢复。这会对应用安全性和用户数据隐私构成极大的威胁,所以必须设置为false,防止数据泄漏。

b). 在SDK支持的情况下,Android必须使用v2签名,这将对APK文件的修改做更多的保护。

c). 确保应用发布的版本的android:debuggable属性设置为false。

建议的遵守的开发规范如下:

a). 在Android 4.2以上,对安全性较高的应用可在Activity中,对Activity所关联的Window应用WindowManager.LayoutParams.FLAG_SECURE,防止被截屏、录屏。对于其他的Window的窗口,如Dialog、DialogFragment等,根据需要也进行相应的保护。

 

posted @ 2019-12-04 19:20  灰色飘零  阅读(1235)  评论(0编辑  收藏  举报