UI界面是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计。性能优化都需要有一个目标,UI的性能优化也是一样。你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望。
我们可以从人机交互心理学的角度来考虑这个问题。研究表明,0-100毫秒以内的延迟对人来说是瞬时的,100-300毫秒则会感觉明显卡顿,300-1000毫秒会让用户觉得“手机卡死了”,超过1000ms就会让用户想去干别等事情了。
这是人类心理学最基础的理论,如果网页在3-4秒内还没加载出任何内容,用户就会放弃了。把这些数据应用到app的加载,不难明白加载时间是越短越好。
对于开发过程,出现卡顿的主要原因是主线程做了一些不该做的事,或者主线程做不了事情了。
卡顿:从用户角度说,App操作起来缓慢,响应不及时,列表滑动一顿一顿的,动画刷新不流畅等等一些直观感受。从系统角度来说,屏幕刷新的帧率不稳定,无法保证每秒绘制60帧,也就是说有掉帧的情况发生。
主线程主要是做以上四个方面的工作,如果在主线程做一些耗时操作(网络请求、IO读写等),或者被其他线程挂起(GC),那么页面刷新无法在16ms内完成,就会出现掉帧的情况。
大家应该都对android studio里xml布局编辑器很熟悉了,搭建这些view的时候,一定要留意屏幕右上角的组件树(Component Tree)。套嵌的子view越深,组件树就越复杂,渲染起来也就越费时间,layout尽量不要超过5层,层级的减少,从而达到结构清晰,渲染速度快的效果。顺着这个逻辑,布局优化分为重用、合并、按需载入。
< include>标签可以在一个布局中引入另外一个布局,这个的好处显而易见,比如项目头部栏:左上角返回图标,
在不同的xml上引用,也可以写成一个基类,供给继承当前BaseActivity的类头部状态栏。
首先我们心中要有一个大原则:尽量保持布局层级的扁平化。在这个大原则下我们要知道:
在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,才会让子View调用2次onMeasure。Measure的耗时越长那么绘制效率就低。
如果非要是嵌套,那么尽量避免RelativeLayout嵌套RelativeLayout。
< merge/>主要用来去除不必要的FrameLayout。它的使用最理想的情况就是你的根布局是FrameLayout,同时没有使用background等属性。这时可以直接替换。因为我们布局外层就是FrameLayout,直接“合并”。
我们还可以这样使用,减少一层RelativeLayout。
用TextView同时显示图片和文字;效果如下:
这种效果很常见,一般实现方法是这样。最后放在一个ListView或者RecyclerView里面,就能做出一排出来,并且有分界线
这样写层级太多,不易于处理,这样处理就可以减少几次渲染。
按需载入ViewStub
ViewStub是一个轻量级的View,不占布局位置,占用资源非常小。用法很简单,一旦ViewStub可见或是被inflate了,ViewStub就不存在了,取而代之的是被inflate的Layout。所以它也被称做惰性控件。
ViewStub viewStub = (ViewStub)this.findViewById(R.id.hint_view);
hintView = viewStub.inflate();
TextView textView = (TextView) hintView.findViewById(R.id.tv);
textView.setText("显示内容");
如果要给中间添加间距,怎么实现呢?当然也很简单,比如添加一个高10dp的View,或者android:layout_marginTop="10dp"等方法。但是增加View违背了我们的初衷,并且影响性能。使用过多的margin其实会影响代码的可读性。
最后,便是约束布局;
在 Android Studio 2.3 版本中新建的Module中默认的布局就是 ConstraintLayout 。如下所示:
进入操作界面,如下图:
具体的使用,就不在这里详细介绍了。