我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android性能优化系列篇UI优化

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android性能优化系列篇UI优化

前言

从网上汇总搜集众多大佬的性能优化文章,整理出来部分知识点,主要包含:

UI优化/启动优化/崩溃优化/卡顿优化/安全性优化/弱网优化/APP深度优化等等等~

本篇是第一篇:UI优化!  [非商业用途,如有侵权,请告知我,我会删除]

一、UI优化

UI优化知识点主要分为三部分:

  • 第一部分,系统为我们做的优化。由于前端中UI展示的特殊性和重要性,Android团队也是在不断想办法提高UI方面的渲染速度,所以也是更新了很多系统优化方案,比如:

硬件加速、黄油计划、RenderThread。

  • 第二部分,我们可以具体实施的优化方案。主要包括:

java代码布局、View重用、异步创建View、xml布局优化、异步布局框架Litho、屏幕适配、Flutter、Jetpack Compose

  • 第三部分,工具使用,主要包括:

Choreographer、monitor、Systrace

1.1 系统做的优化

1.1.1 硬件加速

之前我们说过,一个图形的绘制是CPU,GPU和屏幕三方合作的结果。

Android3.0之前,还没有硬件加速,都是通过CPU进行数据计算,然后通过Skia库进行软件绘制,但是CPU对于图形处理并不高效。

于是从3.0开始,Android支持了硬件加速,到Android4.0默认开启硬件加速。

开启硬件加速后,就是由CPU进行图形缓存数据的绘制。这样CPU和GPU就能比较好的分工,各司其职了。CPU用于控制复杂绘制逻辑、构建或更新DisplayList(基础元素);GPU用于完成图形计算、渲染DisplayList(基础元素)。

这里也找了一张各种场景下,硬件加速前后的流程与加速效果(Android6.0背景):

但是硬件加速也是有缺点的:

  • 启用硬件加速需要更多资源,因此应用会占用更多内存。
  • 比较低的版本,由于有些Canvas API还没有支持,所以使用硬件加速可能会有问题。那么我们就可以手动关闭某个view的硬件加速:
    myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Project Butter

黄油计划,你有可能没怎么听说,但是其实之前两章内容都提到过,Android4.1之后,Google提出了黄油计划,主要包括两个内容:

  • VSYNC
  • Triple Buffering(三重缓存)

这些都熟悉了吧,上两节都说过的,这里再简单提一下:

  • VSYNC

垂直同步信号,每当收到这个信号后,CPU就开始准备Buffer数据,并在16ms之内和GPU把屏幕需要的缓存数据准备好。

  • Triple Buffering(三重缓存)

Android4.1之前,是双缓存机制,大部分是没问题的。但是当CPU/GPU绘制过程较长,超过一个vsync信号周期,一般是16ms,就会导致丢帧,CPU无法使用被GPU或者屏幕占用的缓存区。如果下一帧绘制如果又超时,那么又会丢帧。

所以再加上一个缓存区,这样,CPU、GPU、Display三者都有各自的缓存区,互不影响,就能保证时间的最大化利用,也就能减少上述的情况了。

RenderThread

RenderThread是在Android5.0提出的,从这个名字就能知道,它是一个线程,一个专门执行GL命令的线程,也就是一部分的绘制工作。

有了它之后,当CPU处理数据给GPU后,就不需要等GPU渲染完毕了,而是将一些绘制任务交给RenderThread,这样就能减少主线程的工作,保证画面的流畅。同时还提供了RenderNode,用来做view的属性封装,渲染帧的信息等等。

1.2 优化方案

1.2.1 java代码布局

我们一般都是用XML文件进行布局,但是XML解析也是很耗时的,并在这个解析过程在主线程进行。

所以我们有的时候也许可以通过Java代码或者kotlin进行View的创建?

理论中,这样确实能减少布局加载的消耗时间,但是Java代码创建View太麻烦了,而且无法可视化。

当然,也有一些库可以帮助我们将xml代码转换成java代码,比如X2C(github.com/iReaderAndr… ),但是它并不支持所有的情况,比如merge标签,appCompat兼容控件等等。

所以我们需要在这之中找到平衡点,有的时候,UI简单并且要求高性能的前提下,我们可以试试用这样的方法,即用java代码代替XmL代码。

1.2.2 View重用

参照Recyclerview的做法,我们也可以将一些常用的view保存到缓存池中,这样在不同的界面中就能复用缓存池里面的view。

1.2.3 异步创建view

这是Google提出的一个方案——AsyncLayoutInflater。它可以异步加载布局文件,并且回调给主线程,从而减少主线程耗时。简单贴下主要代码:

new AsyncLayoutInflater(MainActivity.this).inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
        @Override
        public void onInflateFinished(@NonNull View view, int i, @Nullable ViewGroup viewGroup) {
        //回调给主线程
            setContentView(view);
    }
});

1.2.4 xml布局优化

在写xml布局文件的时候,我们要做的也有很多,比如:

  • 减少布局嵌套。多使用ViewStub、Merge、ConstraintLayout来代替。
  • 优化开销。RelativeLayout和 使用weight的LinearLayout 开销比较大,建议使用ConstraintLayout,LinearLayout代替。

1.2.5 异步布局框架Litho

Litho是Facebook开源的一款在Android上高效建立UI的声明式框架。

主要有以下特点:

1)声明式:它使用了声明式的API来定义UI组件。

2)异步布局:它把 measurelayout 都放到了后台线程,只留下了必须要在主线程完成的 draw,这大大降低了 UI 线程的负载

3)视图扁平化:由于 Litho 使用了自有的布局引擎(Yoga),在布局阶段就可以检测不必要的层级、减少 ViewGroups,来实现 UI 扁平化。

4)优化 RecyclerView:Litho 还优化了 RecyclerView 中 UI 组件的缓存和回收方法。

1.2.6 屏幕适配

关于屏幕适配问题,也是老生常谈了。主要有以下几种方案:

  • dp适配方案。

这是系统自带的适配单位,dp是基于屏幕物理分辨率一个抽象的单位,用于说明与密度无关的尺寸和位置。所以它能在不同分辨率的手机上有相对大小的适配性。计算公式是:px=dp * (dpi/160)。但是dpi有可能会被人为调整(比如几部相同分辨率不同尺寸的手机的ppi可能分别是是430,440,450,那么在Android系统中,可能dpi会全部指定为480),所以还是有可能在一些设备上出现适配问题。

  • 宽高限定符适配方案。

简单地说,这个方案就是穷举市面上所有的Android手机的宽高像素值。然后找到对应的文件夹使用下面的资源文件所对应的px值。

但是这方案有个缺陷,就是必须精确命中才行。比如1920x1080的手机就一定要找到1920x1080的限定符,否则就只能用统一的默认的dimens文件了。

所以容错性太低,不推荐。

  • smallestWidth适配方案。

这个方案就是通过手机的宽度值来找到对应限定符文件夹下的资源文件,可以看做宽高限定符屏幕适配方案的升级版。

假如我们的设计图宽为360dp,那么就创建values-sw360dp文件夹,并添加资源文件:

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">1dp</dimen>
    <dimen name="dp_2">2dp</dimen>
    <dimen name="dp_3">3dp</dimen>
    ...
    <dimen name="dp_359">359dp</dimen>
    <dimen name="dp_360">360dp</dimen>
</resources>

很简单,分为360份,然后我们实际写布局文件的时候,直接引用对应的dimen值即可。

然后新建其他设备宽度的文件夹,并在每个文件夹里添加对应的资源文件,这里以400dp为例:

├── class="lazy" data-src/main
│   ├── res
│   ├── ├──values
│   ├── ├──values-sw320dp
│   ├── ├──values-sw400dp
│   ├── ├──...
│   ├── ├──values-sw640dp
<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">1.1111dp</dimen>
    <dimen name="dp_2">2.2222dp</dimen>
    <dimen name="dp_3">3.3333dp</dimen>
    <dimen name="dp_4">4.4444dp</dimen>
    ...
    <dimen name="dp_359">398.8889dp</dimen>
    <dimen name="dp_360">400.0000dp</dimen>
</resources>

也就是说,所有的设备都分为360份了,这样就能保证在不同宽度设备上都能有差不多的效果。

如果我们的设备宽度为400dp,那么就会调用values-sw400dp对应的资源文件,如果找不到,就会向下查找。比如我们宽度是402dp,找不到对应的,就会向上找到400dp对应的资源文件,所以也有比较好的容错性。也是一个比较好的适配方案。

当然这种重复性工作肯定不需要我们自己手动去实现,有专门的插件可以生成相应的文件和文件夹,这里也推荐一个:github.com/ladingwu/di…

  • 今日头条适配方案。

这个大家应该都很熟悉了,主要是通过动态修改density值来保证所有设备的屏幕宽度都是固定的dp值。用到的公式就是px = density * dp

比如设计图宽为360dp,我们只要保证所有设备的宽度都是360dp就能适配了。而宽度的px值我们是已知的,所以就是要修改这个 density 值来完成我们的适配目的。具体代码我就不贴了,网上很多。

这种方案侵入性低,使用方便,是个不错的适配方案。

1.2.7 Flutter

Flutter是 Google 推出并开源的移动应用开发框架,开发者可以通过 Dart 语言开发 App,一套代码同时运行在 iOS 和 Android 平台。

Flutter框架现在也是特别火,实际运用到很多的大厂项目,比如闲鱼今日头条。它相对于Android其实是另外一套APP架构了,它没有基于系统本身的渲染引擎,而是app中自带Skia引擎,虚拟机也是使用的Dart虚拟机。

主要有以下几个特点:

  • 跨平台:现在flutter至少可以跨5种平台,常见的平台:MacOS,Windows ,Linux ,Android ,iOS ,到目前为止,Flutter算是支持平台最多的框架了。良好的跨平台性,大大减少了开发成本。
  • 丝滑般的体验:使用Flutter内置的Material Design(android风格)和Cupertino(ios风格)风格组件,以及丰富的motion API,平滑而自然的滑动效果和平台感知,为用户带来全新的体验。
  • 响应式框架:使用一系列基础组件和响应式框架,可以轻松构建用户界面。使用功能强大且灵活的API可以实现复杂的界面效果。
  • 支持插件:使用插件可以访问平台本地API,如相机,蓝牙,WIFI等等。借助现有的Java,swift ,object c , c++代码实现对原生系统的调用。
  • 60fps超高性能:Flutter编写的应用可以达到60fps(每秒传输帧数)。Flutter采用GPU渲染技术,所以性能很好。完全可以胜任游戏开发。

1.2.8 Jetpack Compose

Jetpack Compose 是用于构建原生 Android 界面的新工具包

原来我们的布局文件都是写在xml文件中的,现在提供了一种新的view构建方式,也就是Compose

它是一种声明式UI,不再使用xml,而是使用kotlin进行UI布局。其实就跟我们之前提到的一点,用java代码去构建view一样的效果。这样就减少了xml解析的时间,提高了效率。

声明式UI。指的是只需要把界面声明出来,不需要手动更新。比如我们这里的Compose只需要写一遍,后续的UI改变会随着变量自动更新。而传统的xml布局方式就无法做到这一点,属于命令式UI,需要我们手动命令纸牌屋UI的修改。

官方也是宣称有以下几点优势:

更少更直观的代码,更强大的功能,能提高开发速度。

最后贴一段代码,感受下Compose的写法:

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      Greeting("Android")
    }
  }
}
​
@Composable
fun Greeting(name: String) {
    Text (text = "Hello $name!")
}
  

复制

1.3 工具篇

1.3.1 Choreographer

Choreographer其实也是一个监控应用帧率的工具。它主要有以下特性:

  • 能获取整体的帧率。
  • 能在线上使用。
  • 获取的帧率几乎是实时的。

主要原理就是利用postFrameCallback计算两次绘制的间隔时间,简单贴下代码:

private long mLastFrameTime;
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
    @Override
    public void doFrame(long frameTimeNanos) {
        if (mLastFrameTime == 0) {
            mLastFrameTime = frameTimeNanos;
        }
        float diff = (frameTimeNanos - mLastFrameTime) / 1000000.0f;//得到毫秒,正常是 16.66 ms
        if (diff > 500) {
            double fps = (((double) (mFrameCount * 1000L)) / diff);
            mFrameCount = 0;
            mLastFrameTime = 0;
            Log.d("doFrame", "doFrame: " + fps);
        } else {
            ++mFrameCount;
        }
        Choreographer.getInstance().postFrameCallback(this);
    }
});

想细细研究的可以看看这个库(github.com/friendlyrob… )

1.3.2 LayoutInspector/Android Device Monitor

LayoutInspectorAndroidStudio种的一个布局检查器,可以通过Tools > Layout Inspector找到,他可以检查应用中的某个界面的视图结构,但是无法查看非调式状态的应用。

如果要看其他应用的布局情况,可以使用Android Device Monitor,在Android Studio 3.1 以后,需要单独从文件夹打开了:

android-sdk/tools/monitor

1.3.3 Systrace

Systrace是分析Android性能问题的神器,获取Systrace文件的方式有两种:

  • 一是AndroidSDK/tools目录下,通过monitor.batAndroid Device Monitor可视化工具得到。
  • 二是通过python脚本获取。

以上就是Android性能优化系列篇UI优化的详细内容,更多关于Android性能UI优化的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android性能优化系列篇UI优化

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android性能优化系列篇UI优化

这篇文章主要为大家介绍了Android性能优化系列篇UI优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

抖音 Android 性能优化系列:Java 锁优化

本文将着重向大家介绍 Slardar 线上锁监控方案的原理与使用方法,以及我们在抖音上发现的锁的经典案例与优化实践。

抖音 Android 性能优化系列:启动优化实践

本篇我们将按照主线程直接优化、后台线程间接优化、全局优化的逻辑,介绍团队在启动优化的实践中遇到的一些比较典型的案例,其间对于业界一些比较优秀的方案也会进行简要介绍。

Android性能优化之运算篇

运算篇1) Intro to Compute and Memory ProblemsAndroid中的Java代码会需要经过编译优化再执行的过程。代码的不同写法会影响到Java编译器的优化效率。例如for循环的不同写法会对编译器优化这段代码
2022-06-06

抖音 Android 性能优化系列:Java OOM 优化之 NativeBitmap 方案

对于 Java 内存泄漏治理,业界已经有比较成熟的方案,这里不做介绍,本文主要针对第二点尝试进行分析和优化。

Taro性能优化之复杂列表篇

本文将以复杂列表的性能优化为主旨,尝试建立检测指标,了解性能瓶颈,通过预加载、缓存、优化组件层级、优化数据结构等多种方式,实验后提供一些技术方案的建议,希望可以给大家带来一些思路。

Android性能优化之网络优化

在移动互联网的快速发展环境下,手机用户日益对网络的使用或体验有着更深度的诉求,因此应用中的网络体验已经显得由此重要。

Android性能优化(一)启动优化

以前做手机的时候,我非常重视app的性能优化。其实一直以来,在工作中我总会去强调性能优化的重要性。但是,很多时候,由于一些外界因素,我们对app的一些性能指标不会那么重视。但是,性能优化依然是做好一个产品的重中之重。试想一下,如果用户费了很
2022-06-06

Android性能优化典范之多线程篇

多线程在Android性能优化中起到非常重要的作用。通过合理地使用多线程,可以提高应用程序的响应速度,加快数据处理和计算速度,提升用户体验。以下是Android性能优化中多线程的一些典范:1. 合理选择线程池大小:线程池是管理线程的重要工具
2023-09-20

Webpack 性能系列四:分包优化

默认情况下,Webpack 会将所有代码构建成一个单独的包,这在小型项目通常不会有明显的性能问题,但伴随着项目的推进,包体积逐步增长可能会导致应用的响应耗时越来越长。

Python 性能快速优化: 系列一

注: 本文的原文地址 quick-python-performance-optimization-part-iPython可能最容易扼杀你的想法,但不是最好的代码实现。尽管强烈反对过早优化,但在 Python 代码中一点点的优化都可能带来巨
2023-01-31

Android 性能优化 ~ 包体积优化实战

概述 用户通常都不愿意去下载一个比较大的程序,特别是不在 WIFI 的情况下。如果你的安装包很小,用户还是愿意下载安装体验下的。现在市面上满足某种需求的 App 通常都会有很多款,如何让用户愿意下载你的 App 来体验?安装包越小,在 WI
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录