【Android】画面卡顿优化列表流畅度一
卡顿渲染耗时如图:

卡顿表现有如下几个方面:
- 网络图片渲染耗时大
- 上下滑动反应慢,甚至画面不动
- 新增一页数据加载渲染时耗时比较大,上下滑动几乎没有反应,画面停止没有交互响应
背景
实际上这套数据加载逻辑已经运行了快一年多了,之前也没有这些问题的。笔者是后面接手的,也没觉得有问题。也许是最初数据量小当时看不出来
运行到今天设计业务数据量是3650条,实际业务数据条数是1100条左右;这个业务数据量原本也不是特别大。所以也没觉得有问题。
直到其他业务组的数据接入后数据量起来了这个列表数据就卡顿的几乎不能用了,而不凑巧被领导知道了,于是就有了本次优化
原本的设计如下:
列表布局:
<android.support.v4.widget.NestedScrollViewandroid:id="@+id/nestedScrollView"android:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"app:layout_behavior="@string/appbar_scrolling_view_behavior"><live.bingoogolapple.refreshlayout.BGARefreshLayoutandroid:id="@+id/mRefreshLayout"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recycleView_playback"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FFFFFFFF"android:nestedScrollingEnabled="false"android:paddingLeft="20dp"android:paddingRight="10dp"android:paddingBottom="8dp"app:layout_behavior="@string/appbar_scrolling_view_behavior" /></live.bingoogolapple.refreshlayout.BGARefreshLayout></android.support.v4.widget.NestedScrollView>
RecyclerView.Adapter数据加载和下面类似:
RecyclerView.Adapter 是用于在 RecyclerView 中展示数据的关键组件之一。下面是使用 RecyclerView.Adapter 的基本步骤:
- 创建自定义的 Adapter 类:首先需要创建一个继承自 RecyclerView.Adapter 的自定义 Adapter 类,该类负责管理数据集合并将数据绑定到 RecyclerView 的 ViewHolder 上。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {// 适配器的代码
}
- 创建 ViewHolder 类:在自定义的 Adapter 类中,需要创建一个继承自 RecyclerView.ViewHolder 的内部类,用于表示 RecyclerView 中的每个子项的视图。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {public static class MyViewHolder extends RecyclerView.ViewHolder {// ViewHolder 的代码}
}
- 实现 Adapter 的方法:在自定义的 Adapter 类中,需要实现一些方法,例如 onCreateViewHolder、onBindViewHolder、getItemCount 等。这些方法用于创建 ViewHolder、绑定数据到 ViewHolder、获取数据集合的大小等操作。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {// 创建 ViewHolder}@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {// 绑定数据到 ViewHolder}@Overridepublic int getItemCount() {// 获取数据集合的大小}
}
- 在 onCreateViewHolder 方法中创建 ViewHolder:在 onCreateViewHolder 方法中,需要创建并返回一个 ViewHolder 对象,用于表示 RecyclerView 中的每个子项的视图。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {// 创建 ViewHolderView itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);return new MyViewHolder(itemView);}
}
- 在 onBindViewHolder 方法中绑定数据到 ViewHolder:在 onBindViewHolder 方法中,需要将数据绑定到 ViewHolder 上,以便在 RecyclerView 中显示。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {// 绑定数据到 ViewHolderMyData data = dataList.get(position);holder.bindData(data);}
}
- 将 Adapter 与 RecyclerView 关联:最后,需要将自定义的 Adapter 与 RecyclerView 关联起来,以便在 RecyclerView 中展示数据。
RecyclerView recyclerView = findViewById(R.id.recycler_view);
MyAdapter adapter = new MyAdapter(dataList);
recyclerView.setAdapter(adapter);
在上面的代码中,dataList 是数据集合,R.layout.item_layout 是每个子项的布局文件。通过以上步骤,就可以使用 RecyclerView.Adapter 在 RecyclerView 中展示数据了。
Glide图片加载库使用
Glide.with(context).load(imgUrl).into(holder.imageview);
BGARefreshLayout上拉加载更多组件使用方式叠加NestedScrollView
BGARefreshViewHolder bgaNormalRefreshViewHolder = new BGANormalRefreshViewHolder(this, true);mRefreshLayout.setRefreshViewHolder(bgaNormalRefreshViewHolder);nestedScrollView = findViewById(R.id.nestedScrollView);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {nestedScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {@Overridepublic void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {NestedScrollView toNesstedScrollView = (NestedScrollView) view;if (scrollY < 5|| toNesstedScrollView.getChildAt(0).getMeasuredHeight()== view.getMeasuredHeight()) {return;}int height = toNesstedScrollView.getChildAt(0).getMeasuredHeight()- view.getMeasuredHeight();if (scrollY == height) {// 为BGARefreshLayout 设置代理if(mRefreshLayout.getDelegate()==null){mRefreshLayout.setDelegate(XXXXActivity.this);}mRefreshLayout.beginLoadingMore();}}});}
内存上到没有太多可书写的,基本没有涉及内存方面的问题
设定优化方向和目标
画面卡顿的由来
Android 屏幕渲染 16ms 柱形图是指在 Android 应用程序中,屏幕渲染所花费的时间以柱形图的形式进行可视化展示。这个柱形图通常用于监测应用程序的性能,特别是在绘制 UI 时所花费的时间。
在 Android 中,每秒钟需要渲染 60 帧的屏幕,即每帧的时间限制为 16 毫秒(1 秒 = 1000 毫秒 / 60 帧 ≈ 16.67 毫秒)。如果屏幕渲染超过 16 毫秒,就会导致丢帧(屏幕卡顿)。
柱形图中的每个柱子代表一帧的渲染时间。如果柱子的高度超过 16 毫秒,就表示该帧的渲染时间超过了理想的 16 毫秒限制。柱形图越高,表示渲染时间越长,应用程序的性能可能会受到影响。
通过观察柱形图,开发者可以判断应用程序在绘制 UI 时是否存在性能问题,并进行相应的优化。优化的目标是尽量保持每帧的渲染时间在 16 毫秒以内,以确保流畅的用户体验。
- 蓝色部分表示绘制时间或者在Java层创建和更新display list的时间。在一个View 实际被渲染前,它需要先转换为GPU能识别的格式。简单来说可能就是几个绘制命令,复杂一点,我们可能在嵌入了一条从canvas获取的自定义路径。这一步完成之后,输出结果就会被系统作为display list缓存起来。蓝色部分记录了这一帧对所有需要更新的view完成这两步花费的时间。当它很高的时候,说明有很多view突然无效(invalidate)了,或者是有几个自定义view在onDraw函数中做了特别复杂的绘制逻辑
优化方向一:清理布局xml中并没有用到或者被设置无效(invalidate)的view组件,减少布局嵌套层级 - 红色部分代表执行时间,也就是Android 2D渲染引擎(OpenGL)执行display list的时间。为了将变化绘制在屏幕上,Android需要使用OpenGL ES API来绘制这些display list信息,OpenGL最终将数据传给了GPU,然后GPU渲染到屏幕上。View越复杂,OpenGL绘制所需要的命令也越复杂。如果红色这一段比较高,复杂的view都可能是罪魁祸首。还有值得注意的是比较大的峰值,这说明有些view重复提交了,也就是绘制了多次,而它们可能并不需要重绘
优化方向二:采用局部更新view策略 - 橙色部分代表处理时间,更进一步,就是CPU告诉GPU渲染已经完成的时间。这部分是阻塞的,CPU会等待GPU知道确认收到了命令,如果这里比较高,说明GPU做的任务太多了,通常是由于很多复杂的view绘制从而需要过多的OpenGL渲染命令去处理
看下面这张渲染耗时图柱,都破了屏幕了,底部那条红线就没放眼里蛤!

开启渲染耗时图柱开关
一般都在开发者选项-GPU呈现模式分析:

设定优化目标为京东首页在同一机型上的交互表现
京东首页交互流畅度如下:

分以下阶段进行解析当前问题的症结点
- 当前的设计是否满足交互流畅度。流畅度是否能达到京东首页的体感?设计数据只加载文字;加载文字后再加载静态图片;测试验证当前布局、数据逻辑加载的交互体感情况。如不满足那基本就能确定是布局和数据加载逻辑有缺陷,则需要进行重构或重写
- 在第1条满足的基础上,测试同一个网络图片加载到所以列表子项里展示。记录交互体感和京东首页进行对比分析
- 测试单列动态图片加载效果并记录
- 再次测试双列动态图片加载效果并记录
=================================请看下一章
【Android】画面卡顿症结点分析二
smartApi接口开发工具推荐
历时一年半多开发终于smartApi-v1.0.0版本在2023-09-15晚十点正式上线
smartApi是一款对标国外的postman的api调试开发工具,由于开发人力就作者一个所以人力有限,因此v1.0.0版本功能进行精简,大功能项有:
- api参数填写
- api请求响应数据展示
- PDF形式的分享文档
- Mock本地化解决方案
- api列表数据本地化处理
- 再加上UI方面的打磨
下面是一段smartApi使用介绍:

下载地址:
https://pan.baidu.com/s/1kFAGbsFIk3dDR64NwM5y2A?pwd=csdn
相关文章:
【Android】画面卡顿优化列表流畅度一
卡顿渲染耗时如图: 卡顿表现有如下几个方面: 网络图片渲染耗时大上下滑动反应慢,甚至画面不动新增一页数据加载渲染时耗时比较大,上下滑动几乎没有反应,画面停止没有交互响应 背景 实际上这套数据加载逻辑已经运行…...
SNP应邀参加2023中国企业数字化转型峰会暨赛意用户大会
创新驱动科技,数智驱动未来。如今,我国产业数字化进程提速升级,数字产业化规模持续壮大。数据显示,2022年,我国数字经济规模达50.2万亿元,总量稳居世界第二。数字经济已经成为推动传统产业转型升级、促进高…...
黑豹程序员-架构师学习路线图-百科:Knife4j API接口文档管理
文章目录 由来:接口文档第一代:Swagger第二代:Knife4j界面 由来:接口文档 古老编程是一个语言前后端通吃,ASP、JSP、PHP都是如此。 但随着项目规模变大,项目团队也开始壮大,岗位职责开始细分&a…...
PHP安全问题:远程溢出、DoS、safe_mode绕过漏洞
一、Web 服务器安全 PHP 其实不过是 Web服务器的一个模块功能,所以首先要保证 Web服务器的安全。当 然 Web服务器要安全又必须是先保证系统安全,这样就扯远了, 无穷无尽。PHP可以和各种 Web 服务器结合,这里也只讨论 Apache。非常建议以 chroot 方式安装启动 Apache,这样…...
2023云计算发展
未来的云计算世界将是一个充满着无限可能和创意的世界。在这个世界中,人们可以通过云计算技术实现更加便捷、安全、高效的日常生活,同时可以探索更加广阔、神奇的世界。 智能家居将成为云计算的新宠。未来,人们可以通过语音、手势、传感器等…...
javaSE学习笔记(六)泛型,异常
五、泛型 泛型的由来:通过Object转型问题引入--为了解决安全隐患 早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换异常的问题 泛型作用 提高安全性(将运行期的错误转换到编译期) 省去强转的麻烦,取…...
C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发006:基于redis查找玩家姓名+游戏业务实现总结
文章目录 1 Redis的安装与API的使用1.1 安装目录及环境变量1.2 设置远程客户端连接和守护进程1.3 启动redis1.4 Hiredis API的使用1.5 我的动态库和头文件 2 Redis的使用2.1 初始化时候2.2 结束的时候 3 测试4 Makefile5 游戏业务总结 1 Redis的安装与API的使用 1.1 安装目录及…...
数字政府!3DCAT实时云渲染助推上海湾区数字孪生平台
数字孪生,是一种利用物理模型、传感器数据、运行历史等信息,在虚拟空间中构建实体对象或系统的精确映射,从而实现对其全生命周期的仿真、优化和管理的技术。数字孪生可以应用于各个领域,如工业制造、智慧城市、医疗健康、教育培训…...
react之Component存在的2个问题
问题 只要执行setState(),即使不改变状态数据,组件也会重新render()只当前组件重新render(),就会自动重新render子组件 原因 Component中的shouldComponentUpdate()总是返回true 思路 只有当组件的state或props数据发生改变时才重新rend…...
【论文阅读】Generating Radiology Reports via Memory-driven Transformer (EMNLP 2020)
资料链接 论文原文:https://arxiv.org/pdf/2010.16056v2.pdf 代码链接(含数据集):https://github.com/cuhksz-nlp/R2Gen/ 背景与动机 这篇文章的标题是“Generating Radiology Reports via Memory-driven Transformer”…...
IP协议相关技术
文章目录 IP协议相关技术仅凭IP无法完成通信DNSARP IP协议相关技术 仅凭IP无法完成通信 人们在上网的时候其实很少直接输入某个具体的IP地址。 在访问Web站点和发送、接收电子邮件时,我们通常会直接输入Web网站的地址或电子邮件地址等那些由应用层提供的地址&…...
Visual Studio2022安装教程【图文详解】(大一小白)编译软件
工欲善其事,必先利其器。想要学好编程,首先要把手中的工具利用好,今天小编教一下大家如何下载安装并使用史上最强大的编译器--Visual Studio🍗 一.Visual Studio下载及安装 https://visualstudio.microsoft.com/ 打开文件 点击.ex…...
matlab 点云最小二乘拟合平面(PCA法)
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 见:matlab 点云最小二乘拟合平面(PCA法详细过程版)。 二、代码实现 clc;clear; %% --------...
socks5代理和https代理有什么不同?各自有哪些优点?
socks5代理和https代理是两种不同的代理服务,它们在实现方式、安全性和协议特点等方面存在差异。下面我们来详细了解一下这两种代理的优点。 一、socks5代理的优点 1. 速度快 socks5代理采用了TCP协议,能够有效地减少网络延迟和数据传输速度慢的问题&…...
springboot,spring框架返回204 status code的时候,会吞掉返回值
背景 发现有个有意思的现象,就是当你的接口返回204的 HTTP status code 的时候,会自动把 response body 吃掉,即使代码里是有返回的。例如 (其实204本身就是NO_CONTENT的意思,不过我是真没想到真干掉了返回࿰…...
6-爬虫-scrapy解析数据(使用css选择器解析数据、xpath 解析数据)、 配置文件
1 scrapy解析数据 1.1 使用css选择器解析数据 1.2 xpath 解析数据 2 配置文件 3 整站爬取博客–》爬取详情–》数据传递 scrapy 爬虫框架补充 # 1 打码平台---》破解验证码-数字字母:ddddocr-计算题,滑块,成语。。。-云打码,超…...
idea 一直卡在maven正在解析maven依赖
修改maven Importing的jvm参数 -Xms1024m -Xmx2048m...
警告:未配置spring boot 配置注解处理器
前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱 问题 我再使用ConfigurationProperties(prefix “redisson”)去加载配置文件中的属性的时候,发现idea有个警告 并且配…...
详解虚拟DOM的原理
Virtual DOM(虚拟DOM)是一种编程概念,它是对真实DOM的轻量级抽象表示。在前端开发中,直接操作真实DOM是昂贵的,尤其是当涉及到大量的DOM更新时。Virtual DOM的出现,为优化和提高Web应用的性能提供了一个有效…...
开设自己的网站系类03安装数据库(centos版)
编者买了一个服务器打算自己构建一个网站,用于记录生活。网站大概算是一个个人博客吧。记录创建过程的一些步骤。 前面已经讲过配置服务器的程序运行环境 网站运行还需要数据库,本篇文章则是安装数据库的内容。 卸载mariadb 查看是否有安装 mariadb&…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
