1. Activity间的数据通信,对于量比较大避免使用 Intent + Parcelable 的方式,可以考 虑 EventBus等替代方案,以免造成 TransactionTooLargeException。(使用方法:http://blog.csdn.net/bskfnvjtlyzmv867/article/details/71480647)
2. 持久化储存放在onPause/onStop中进行。
3. Activity通过隐式Intent跳转,需要使用resolveActivity检查,避免找不到合适的调用组件,造成ActivityNotFoundException的异常。
public void viewUrl(String url, String mimeType){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimeType);
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null){
try {
startActivity(intent);
}catch (ActivityNotFoundException e){
Log.e("ouyang", "can not find activity");
}
}
}
4. 避免在Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,使用IntentService或者其他异步机制完成。
5. 避免在BroadcastRecevier#onReceive()方法中执行耗时操作,如果要执行耗时操作,放到IntentService中完成,不应该在BroadcastReceiver内创建子线程去做。
说明:
由于此方法也在主线程中,耗时操作会导致UI不流畅。可以使用IntentService,创建HandlerThread或者调用Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其他Worker线程执行onRecevier方法。BroadcastReceiver#onReceiver()方法耗时操作10秒,会造成ANR,可能被系统杀死。
6. 避免使用隐式Intent广播命敏感信息,可能会被其他已注册的app监听到。
说明:
隐式广播会造成其他已注册的接收者也可接收,可能会做一些危险的操作。如果发送的是有序广播,优先级比较高的恶意广播可能会丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。
如果广播仅限于应用内,则可用LocalBroadcastManager#sendBroadcast(),避免敏感信息外泄和Intent拦截风险。
7. 添加Fragment时,确保FragmentTransaction#commit()在Activity#onPostResume()或者FragmentActivity#onResumeFragments()内调用。不要随意使用FragmentTransaction#commitAllowingStateLoss()来替代,需要慎重。
8. 不要在Activity#onDestory()中执行释放资源的工作,例如一些工作线程的销毁和停止,因为onDestory()执行的时机可能较晚。可根据实际需要,在Activity#onPause()/onStop()中结合isFinishing()来判断执行。
9. 如非必须,避免使用嵌套的Fragment。
说明:
Fragment嵌套的一些坑:
1) onActivityResult()方法的处理错乱,内嵌的Fragment可能接收不到该方法的回调,需要由宿主Fragment进行转发处理;
2) 突变动画效果;
3) 被继承的setRetainInstance(),导致在Frament重建时多次触发不必要的逻辑;
10. 总是使用显式Intent启动或者绑定Service,且不要为服务申明IntentFilter,保证应用的安全性。如果确实需要隐式调用,必须搭配只用Intent#setPackage()方法设置Intent的指定包名,这样可以充分消除目标服务的不确定性。
11. Service需要多线程并发处理多个启动请求,建议使用IntentService,可避免各种复杂的设置。
12. 不要在Android的Application对象中缓存数据。基础组件之间的数据共享请使用Intent等机制,也可使用SharedPreference等数据持久化机制。
13. 使用Toast时,建议定义一个全局Toast对象。
14. 使用 Adapter的时候,如果你使用了 ViewHolder做缓存,在 做缓存,在 getView()的 方法中无论这项 convertView 的每个子控件是否需要设置属性 的每个子控件是否需要设置属性 (比如某个 TextView设置的文本可能为 null,某个按钮的背景色为透明控件颜等 ),都需 要为其显式设置属性 (Textview 的文本为空也需要设置 文本为空也需要设置 文本为空也需要设置 setText(""),背景透明也需要 ,背景透明也需要 设置 ),否则在滑动的过程中,因为 ,否则在滑动的过程中因为 ,否则在滑动的过程中因为 adapter itemadapter itemadapter itemadapter itemadapter itemadapter itemadapter item adapter item adapter item复用的原因,会出现内容显示错 复用的原因,会出现内容显示错 复用的原因,会出现内容显示错 复用的原因,会出现内容显示错 乱。
15. Activity或Fragment中动态注册BroadcastReceiver时,registerReceiver()和unregisterReceiver()要成对出现。
说明:
若没有将已注册的BroadcastReceiver及时注销,有可能造成内存泄露,家中SystemService的负担。
16. 尽量减少ViewGroup嵌套,增加渲染时间。
17. 在Activity中显示对话框或弹出浮层时,尽量使用DialogFragment,而非Dialog或者AlertDialog,这样便于随Activity生命周期对话框/弹出浮层的生命周期。
18. 灵活使用布局,推荐 Merge、ViewStub来优化布局,尽可能多的减少 来优化布局,尽可能多的减少 UI 布局层级,推荐使用 FrameLayout ,LinearLayout 、RelativeLayout 次之。
19. 不能在Activity没有完全显示时显示PopupWindow和Dialog。
20. 尽量不适用AnimationDrawable(少量还是可以),它初始化的时候就将所有加载到内存中,特别占内存,而且还不能释放,释放后下次进入加载时会报错。
21. 不能使用ScrollView包裹ListView/GridView/ExpandableListView,因为这样会把所有的item全部都加载到内存中,需要消耗巨大的内存和CPU取绘制图面。推荐使用NestedScrollView。
22. 不要通过Intent在Android基础组件中传递大数据(1M),可能导致OOM。
23. 在Application的业务初始化代码中加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。
24. 新建线程时,必须通过线程池提供(AsyncTask,ThreadPoolExecutor或者其他形式自定义的线程池),不允许在应用中显示创建线程。
说明:
使用线程池的好处是在减少在创建和销毁线程上所花的时间以及系统资源开销,解决资源不足问题。如果不使用线程池,有可能造成创建大量同类线程而导致消耗完内存或者“过度切换”的问题。另外创建匿名线程不便于后续的资源使用分析,对性能分析等会造成困扰。
25. 线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更见明确的线程池的运行规则,规避资源耗尽的风险。
说明:
Executors返回的线程池对象的弊端如下:
1) FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM;
2) CachedThreadPool和ScheduledThreadPool:允许创建线程数为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
26. 不要在非UI线程中初始化ViewSub,否则会返回null;
27. 尽量减少不同APP之间的进程通信及拉起行为。拉起行为导致占用系统资源,影响用户体验。
28. 新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。
super.setName("ThreadName");
29. ThreadPoolExecutor设置线程存活时间(setKeepAliveTime),确保闲置线程释放。
30. 禁止在多进程之间用SharedPreference共享数据。
31. 谨慎使用多进程,多进程虽然能够降低主进程的内存压力,但会遇到如下问题:
1)不能实现完全推出所有Activity的功能;
2) 首次进入新启动进程的页面时会有延时的现象;
3) 应用多进程,Application会实例化多次,需要考虑在不同进程中初始化不同部分的代码;
4) 多进程使用SharedPreference共享数据不稳定。
32. 任何时候不要硬编码文件路径,请使用Android 文件系统的API
说明:
Android应用 提供内部和外存储,分别用于存放自身数据以及应用产生的用户数据。可以通过相关 API 接口获取对应的目录,进行文件操作。
android.os.Environment#getExternalStorageDirectory()
android.os.Environment#getExternalStoragePublicDirectory()
android.content.Context#getFilesDir()
android.content.Context#getCacheDir
33. 当时用外部存储的时候,要先检查外部存储的可用性。
34. 应用间共享文件时,不要通过放宽文件系统权限的方式取是实现,而应使用FileProvider。
35. SharedPreference推荐使用apply异步提交数据,commit效率没那么好,除非需要立即使用提交后的数据。
36. 数据库Cursor必须确保使用后关闭
37. 多线程操作写入数据库时,需要使用事务,以免出现同步问题。
说明:
插入数据之前,使用db.beginTransaction(),使用完之后db.setTransactionSuccessful()。
38. 大数据写入数据库时,请使用事务或其他能够提高I/O效率的机制,保证执行速度。
39. 执行SQL语句时,应使用SQLiteDataBase#insert(),update(),delete(), 不要使用SQLiteDataBase#execSQL(),以免SQL注入风险。
40. 使用ListView、ViewPager、RecylerView、CardView等组件使用图片时,应做好图片缓存,避免始终持有图片导致内存泄露,也避免图片重建,引起性能问题,推荐使用Glide等图片库。
41. png图片使用tinypng或者类似工具压缩处理,减少包体积。
42. 应根据实际需要,压缩图片,而不是直接显示原图。
43. 使用完的图片,应及时回收,释放宝贵的内存。
44. 在Activity.onPause或onStop回调中,关闭当前activity正在执行的动画;
45. 动画或者其他异步任务结束时,应考虑回调时刻的环境是否还支持业务处理。不判空,会产生空指针异常。
46. 使用ARGB_565代替ARGB_888,前者不支持透明度
47. 尽量减少Bitmap(BitmapDrawable)的使用,尽量使用纯色(ColorDrawable)、渐变色(GradientDrawable)、StateSelector(StateListDrawable)等与shape结合构建绘图。
48. 有强依赖onAnimationEnd回调的交互时,如动画播放结束才能操作页面,onAnimationEnd可能会因各种异常没被回调,建议加上超时保护或通过postDelay替代onAnimationEnd。
49. 执行完Animation,调用View.clearAnimation()释放资源。
50. 使用PendingIntent时,禁止使用空Intent,同时禁止使用隐式Intent说明;
51.