您现在的位置是:首页 >技术杂谈 >Android中级——性能优化网站首页技术杂谈

Android中级——性能优化

松仔log 2023-05-14 08:00:02
简介Android中级——性能优化

布局优化

UI渲染机制

  • 画面流畅需要帧数为60帧每秒
  • Android通过VSYNC信号触发对UI的绘制,其间隔时间是1000ms/60=16ms(即1000ms内显示60帧画面的单位时间)
  • 故需在16ms之内完成绘制才可以保证画面的流畅
  • 否则会造成丢帧,如一次绘制耗时20ms,当16ms时系统发出VSYNC信号还未绘制完,下一个帧就会被丢弃,直到下次信号才开始绘制,导致16*2ms内都显示同一帧画面(即卡顿)

利用 开发者选项 / Profile GPU Rendering / On srceen as bars 工具可检查UI渲染时间

  • 蓝色:测量绘制Display List的时间
  • 红色:OPenGL渲染Display List所需要的时间
  • 黄色:CPU等待GPU处理的时间
  • 绿色横线:VSYNC时间16ms,需尽量将所有条形图控制在绿线下
    在这里插入图片描述

避免Overdraw

过度绘制会浪费CPU、GPU资源,如系统会默认绘制Activity的背景,若再绘制一个重叠背景则Overdraw了

利用 开发者选项 / Enable GPU Overdraw工具可通过颜色判断Ovedraw的次数,颜色越深表示绘制次数越多

在这里插入图片描述

优化布局层级

对View的测量、布局和绘制都是通过对View树的遍历来操作,建议View树的高度不超过10层,如将RelativeLayout替换嵌套的LinearLayout降低高度

利用<include>重用Layout

如下为一个共性的TextView,将宽高设为0可让开发者在使用时对其赋值

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:gravity="center"
    android:textSize="30sp"
    android:text="common ui">
</TextView>

通过include的layout属性引用

<?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/common_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

使用<ViewStub>实现View的延迟加载

如查看的内容只有在点击某个按钮时才会加载

  • ViewSub只会在显示时才去渲染布局
  • setVisibility(View.GONE)在初始化布局树的时候就已经添加布局

如下为要加载的view_stub_item.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/img"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/ic_launcher">
</ImageView>

主布局中ViewStub通过layout属性引用布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/vis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="visible" />

    <Button
        android:id="@+id/inflate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="inflate" />

    <ViewStub
        android:id="@+id/viewStub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout="@layout/view_stub_item" />

</LinearLayout>

获取到ViewStub后,可利用以下两种方式加载

  • setVisibility(View.VISIBLE)
  • inflate(),还可以返回被inflate的Layout
public class MainActivity extends AppCompatActivity {

    ViewStub viewStub;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewStub = (ViewStub) findViewById(R.id.viewStub);
        findViewById(R.id.vis).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewStub.setVisibility(View.VISIBLE);
            }
        });
        findViewById(R.id.inflate).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                View inflateView = viewStub.inflate();
                ImageView imageView = (ImageView) inflateView.findViewById(R.id.img);
            }
        });
    }
}

Hierarchy View

通过SDK/Tool/monitor.bat,打开Android Device Monitor(打开先需关闭AS),再运行程序,布局如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

在Hierarchy View,我们可以看到三层的LinearLayout且没有分支,说明是冗余的

在这里插入图片描述

选择某个View,点击右上角的"Obtain layout time…",可获取布局测量、摆放、绘制的时间,绿黄红颜色表示绘制效率的好中差

在这里插入图片描述

内存优化

获取内存信息

在开发者模式中找到内存相关信息

在这里插入图片描述

Profiler

可利用AS底部的Profiler实时监控程序的内存使用情况

  • 当内存泄漏时,内存会持续增高
  • 当发生GC时,内存会突然减少

在这里插入图片描述

TraceView

TraceView是一个可视化性能调查工具,用于分析TraceView log,可利用Debug类在onCreate()开启监听,onDestroy()时结束监听

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Debug.startMethodTracing();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Debug.stopMethodTracing();
    }
}

生成的dmtrace.trace存放在以下路径

在这里插入图片描述

此外,还可以通过Android Device Monitor的start method profiling

  • Trace:跟着方法执行的全部过程,资源消耗大
  • Sample:按照指定频率抽样调查,需要较长执行时间获取准备样本

在这里插入图片描述
用Android Device Monitor打开生成的Log,上半部分显示方法执行时间的时间轴,每一行代表一个线程,不同颜色的方块代表下面不同的执行方法

在这里插入图片描述

下半部分为具体方法在所处时间段内的各种类型时间及所占百分比

  • Incl CPU Time——某方法占用的CPU时间
  • Excl CPU Time——某方法本身(不包括子方法)占用的CPU时间
  • Incl Real Time——某方法真正执行时间
  • Excl Real Time——某方法本身(不包括子方法)真正执行时间
  • Calls+RecurCalls——调用次数+递归回调次数

如果Incl CPU Time时间长,但Calls+RecurCalls次数少,则应该优化方法

MAT(Memory Analyzer Tool)

点击Android Device Monitor的Update Heap更新堆数据,在Heap标签点击Cause GC,再点击Dump HPROF File保存文件

在这里插入图片描述

利用Sdkplatform-toolshprof-conv.exe转换格式

在这里插入图片描述

打开MAT选择Open Dump File

在这里插入图片描述

  • Histogram:查看内存中每个对象的数量、大小和名称
  • Dominator Tree:按照对象大小进行排序,并显示对象之间的引用结构,可找出大对象

dumpsys

dumpsys 可以列出系统相关的信息和服务状态

命令功能
activityActivity栈信息
meminfo内存信息
procstats内存状态
package包信息
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。