Android性能优化分类
- 卡顿优化
- 内存优化
- 电量优化
- 网络优化
- 启动优化、安装包体积优化
UI界面是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计。性能优化都需要有一个目标,UI的性能优化也是一样。你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望。
我们可以从人机交互心理学的角度来考虑这个问题。研究表明,0-100毫秒以内的延迟对人来说是瞬时的,100-300毫秒则会感觉明显卡顿,300-1000毫秒会让用户觉得“手机卡死了”,超过1000ms就会让用户想去干别等事情了。
这是人类心理学最基础的理论,如果网页在3-4秒内还没加载出任何内容,用户就会放弃了。把这些数据应用到app的加载,不难明白加载时间是越短越好。
对于开发过程,出现卡顿的主要原因是主线程做了一些不该做的事,或者主线程做不了事情了。
卡顿优化
卡顿:从用户角度说,App操作起来缓慢,响应不及时,列表滑动一顿一顿的,动画刷新不流畅等等一些直观感受。从系统角度来说,屏幕刷新的帧率不稳定,无法保证每秒绘制60帧,也就是说有掉帧的情况发生。
- 布局渲染(解析、测量、布局、渲染)
- 动画执行
- Binder通信
- 界面响应
主线程主要是做以上四个方面的工作,如果在主线程做一些耗时操作(网络请求、IO读写等),或者被其他线程挂起(GC),那么页面刷新无法在16ms内完成,就会出现掉帧的情况。
1,布局渲染
大家应该都对android studio里xml布局编辑器很熟悉了,搭建这些view的时候,一定要留意屏幕右上角的组件树(Component Tree)。套嵌的子view越深,组件树就越复杂,渲染起来也就越费时间,layout尽量不要超过5层,层级的减少,从而达到结构清晰,渲染速度快的效果。顺着这个逻辑,布局优化分为重用、合并、按需载入。
重用< include/>
< include>标签可以在一个布局中引入另外一个布局,这个的好处显而易见,比如项目头部栏:左上角返回图标,
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="@color/background"
android:layout_height="48dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:src="@drawable/icon"/>
<TextView
tools:text="当前界面标题"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textColor="@color/white" />
<TextView
tools:text="右边功能按钮"
android:layout_width="wrap_content"
android:gravity="center"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:textSize="16sp"
android:textColor="@color/white" />
</RelativeLayout>
在不同的xml上引用,也可以写成一个基类,供给继承当前BaseActivity的类头部状态栏。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/title_bar"/>
</RelativeLayout>
合并,减少嵌套
首先我们心中要有一个大原则:尽量保持布局层级的扁平化。在这个大原则下我们要知道:
在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,才会让子View调用2次onMeasure。Measure的耗时越长那么绘制效率就低。
如果非要是嵌套,那么尽量避免RelativeLayout嵌套RelativeLayout。
< merge/>主要用来去除不必要的FrameLayout。它的使用最理想的情况就是你的根布局是FrameLayout,同时没有使用background等属性。这时可以直接替换。因为我们布局外层就是FrameLayout,直接“合并”。
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/title_bar"/>
</merge>
我们还可以这样使用,减少一层RelativeLayout。
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="48dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:src="@drawable/icon_back_1"/>
<TextView
android:layout_gravity="center_horizontal"
android:text="标题"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textColor="@color/black" />
<TextView
android:text="确定"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:gravity="center"
android:layout_height="48dp"
android:layout_alignParentRight="true"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:textSize="16sp"
android:textColor="@color/black" />
</merge>
用TextView同时显示图片和文字;效果如下:
这种效果很常见,一般实现方法是这样。最后放在一个ListView或者RecyclerView里面,就能做出一排出来,并且有分界线
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@color/white"
android:id="@+id/rl_layout"
android:layout_width="match_parent"
android:minHeight="?android:attr/listPreferredItemHeight"
android:layout_height="120px">
<TextView
android:layout_toRightOf="@+id/item_fgmelist_img"
android:id="@+id/item_fgmelist_tv"
android:gravity="center"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的消息"
android:textColor="#FF333333"
android:textSize="28px"
/>
<ImageView
android:id="@+id/item_fgmelist_img"
style="@style/left_right"
android:src="@mipmap/personal"
android:layout_centerVertical="true"
android:layout_width="64px"
android:layout_height="64px"/>
<ImageView
android:layout_marginRight="28px"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@mipmap/path"
android:layout_width="16px"
android:layout_height="26px"/>
<View
android:layout_alignParentBottom="true"
android:layout_marginLeft="28px"
android:background="@color/bg_line"
android:layout_width="match_parent"
android:layout_height="1px"/>
</RelativeLayout>
这样写层级太多,不易于处理,这样处理就可以减少几次渲染。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:drawableLeft="@drawable/personal"
android:drawableRight="@drawable/path"
android:drawablePadding="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textSize="16sp"
android:text="我的消息"
android:background="@color/white"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="120px" />
</LinearLayout>
按需载入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("显示内容");
Space控件
如果要给中间添加间距,怎么实现呢?当然也很简单,比如添加一个高10dp的View,或者android:layout_marginTop="10dp"等方法。但是增加View违背了我们的初衷,并且影响性能。使用过多的margin其实会影响代码的可读性。
<Space
android:layout_width="match_parent"
android:layout_height="15dp"/>
最后,便是约束布局;
ConstraintLayout,增强型RelativeLayout
在 Android Studio 2.3 版本中新建的Module中默认的布局就是 ConstraintLayout 。如下所示:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>
- 传统的Android开发当中,界面基本都是靠编写XML代码完成的,而ConstraintLayout和传统编写界面的方式恰恰相反,ConstraintLayout非常适合使用可视化的方式来编写界面,但并不太适合使用XML的方式来进行编写。
- ConstraintLayout 还有一个优点,它可以有效地解决布局嵌套过多的问题。我们平时编写界面,复杂的布局总会伴随着多层的嵌套,而嵌套越多,程序的性能也就越差。ConstraintLayout则是使用约束的方式来指定各个控件的位置和关系的,它有点类似于 RelativeLayout,但远比RelativeLayout要更强大。
进入操作界面,如下图:
具体的使用,就不在这里详细介绍了。