1:布局中不得不使用ViewGroup多重嵌套时,尽量不实用LinearLayout嵌套,改用RelativeLayout,可以有效降低嵌套数,减少绘制时间。
说明:
Android 应用页面上任何一个 View 都需要经过 measure、layout、draw 三个步骤才能被正确的渲染。从 xml layout 的顶部节点开始进行 measure,每个子节点都需要向自己的父节点提供自己的尺寸来决定展示的位置,在此过程中可能还会重新measure (由此可能导致 measure 的时间消耗为原来的 2-3 倍)。节点所处位置越深,嵌套带来的 measure 越多,计算就会越费时。这就是为什么扁平的 View 结构会性能更好。同时,页面拥上的 View 越多,measure、layout、draw 所花费的时间就越久。要缩短这个时间,关键是保持 View 的树形结构尽量扁平,而且要移除所有不需要渲染的View。理想情况下,总共的 measure, layout, draw 时间应该被很好的控制在 16ms以内,以保证滑动屏幕时 UI 的流畅。
要找到那些多余的 View(增加渲染延迟的 view),可以用 Android Studio Monitor里的 Hierarchy Viewer 工具,可视化的查看所有的 view。
2:禁止在非 UI 线程进行 View 相关操作
3:禁止在设计布局时多次为子 View 和父 View 设置同样背景进而造成页面过度绘制,推荐将不需要显示的布局进行及时隐藏。
4:灵活使用布局,推荐 merge、ViewStub 来优化布局,尽可能多的减少 UI布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。
5:不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。
说明:
ScrollView 中嵌套 List 或 RecyclerView 的做法官方明确禁止。除了开发过程中遇到的各种视觉和交互问题,这种做法对性能也有较大损耗。ListView 等 UI 组件自身有垂直滚动功能,也没有必要在嵌套一层 ScrollView。目前为了较好的 UI 体验,更贴近 Material Design 的设计,推荐使用 NestedScrollView。
6:不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
7:使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需要为其显式设置属性(Textview 的文本为空也需要设置 setText(""),背景透明也需要设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错乱。
8:使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示Toast 时不能取消上一次 Toast 消息的情况。即使需要连续弹出 Toast,也应避免直接调用 Toast#makeText。
9:尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会报错。
说明:
Android 的帧动画可以使用 AnimationDrawable 实现,但是如果你的帧动画中如果包含过多帧图片,一次性加载所有帧图片所导致的内存消耗会使低端机发生 OOM异常。帧动画所使用的图片要注意降低内存消耗,当图片比较大时,容易出现 OOM。图片数量较少的 AnimationDrawable 还是可以接受的。
10:不能在 Activity 没有完全显示时显示 PopupWindow 和 Dialog。
说明:
Android Activity 创建时的生命周期,按照 onCreate() -> onStart() -> onResume() ->onAttachedToWindow() -> onWindowFocusChanged() 的顺序,其中在Activity#onAttachedToWindow() 时, Activity 会与它的 Window 关联,这时 UI 才会开始绘制,在 Activity#onWindowFocusChanged() 时,UI 才变成可交互状态,可以提示用户使用。如果在 Window 未关联时就创建对话框,UI 可能显示异常。推荐的做法是在 Activity#onAttachedToWindow() 之 后 ( 其 实 最 好 是Activity#onWindowFocusChanged() 之后)才创建对话框。
11: 在需要时刻刷新某一区域的组件时,建议通过以下方式避免引发全局 layout刷新:
1) 设置固定的 View 大小的宽高,如倒计时组件等;
2) 调用 View 的 layout 方法修改位置,如弹幕组件等;
3) 通过修改 Canvas 位置并且调用 invalidate(int l, int t, int r, int b)等方式限定刷新区域;
4) 通过设置一个是否允许 requestLayout 的变量,然后重写控件的 requestlayout、onSizeChanged 方 法 , 判 断 控 件 的 大 小 没 有 改 变 的 情 况 下 , 当 进 入requestLayout 的时候,直接返回而不调用 super 的 requestLayout 方法。
12:文本大小使用单位 dp,View 大小使用单位 dp。对于 TextView,如果在文字大小确定的情况下推荐使用 wrap_content 布局避免出现文字显示不全的适配问题。
说明:
之所以文本大小也推荐使用 dp 而非 sp,因为 sp 是 Android 早期推荐使用的,但其实 sp 不仅和 dp 一样受屏幕密度的影响,还受到系统设置里字体大小的影响,所以使用 dp 对于应用开发会更加保证 UI 的一致性和还原度。
13:源文件统一采用 UTF-8 的形式进行编码。
14:在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非Dialog/AlertDialog,这样便于随 Activity 生命周期管理对话框/弹出浮层的生命周期。
后续会接着更新补充。