【Android】画面卡顿优化列表流畅度一

卡顿渲染耗时如图:
新增数据卡顿上下滑动不了
卡顿表现有如下几个方面:

  1. 网络图片渲染耗时大
  2. 上下滑动反应慢,甚至画面不动
  3. 新增一页数据加载渲染时耗时比较大,上下滑动几乎没有反应,画面停止没有交互响应

背景

实际上这套数据加载逻辑已经运行了快一年多了,之前也没有这些问题的。笔者是后面接手的,也没觉得有问题。也许是最初数据量小当时看不出来
运行到今天设计业务数据量是3650条,实际业务数据条数是1100条左右;这个业务数据量原本也不是特别大。所以也没觉得有问题。
直到其他业务组的数据接入后数据量起来了这个列表数据就卡顿的几乎不能用了,而不凑巧被领导知道了,于是就有了本次优化

原本的设计如下:

列表布局:

 <android.support.v4.widget.NestedScrollView
            android: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.BGARefreshLayout
                android: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.RecyclerView
                    android: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 的基本步骤:

  1. 创建自定义的 Adapter 类:首先需要创建一个继承自 RecyclerView.Adapter 的自定义 Adapter 类,该类负责管理数据集合并将数据绑定到 RecyclerView 的 ViewHolder 上。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    // 适配器的代码
}
  1. 创建 ViewHolder 类:在自定义的 Adapter 类中,需要创建一个继承自 RecyclerView.ViewHolder 的内部类,用于表示 RecyclerView 中的每个子项的视图。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        // ViewHolder 的代码
    }
}
  1. 实现 Adapter 的方法:在自定义的 Adapter 类中,需要实现一些方法,例如 onCreateViewHolder、onBindViewHolder、getItemCount 等。这些方法用于创建 ViewHolder、绑定数据到 ViewHolder、获取数据集合的大小等操作。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 创建 ViewHolder
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        // 绑定数据到 ViewHolder
    }

    @Override
    public int getItemCount() {
        // 获取数据集合的大小
    }
}
  1. 在 onCreateViewHolder 方法中创建 ViewHolder:在 onCreateViewHolder 方法中,需要创建并返回一个 ViewHolder 对象,用于表示 RecyclerView 中的每个子项的视图。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 创建 ViewHolder
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        return new MyViewHolder(itemView);
    }
}
  1. 在 onBindViewHolder 方法中绑定数据到 ViewHolder:在 onBindViewHolder 方法中,需要将数据绑定到 ViewHolder 上,以便在 RecyclerView 中显示。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        // 绑定数据到 ViewHolder
        MyData data = dataList.get(position);
        holder.bindData(data);
    }
}
  1. 将 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() {
                @Override
                public 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 毫秒以内,以确保流畅的用户体验。

  1. 蓝色部分表示绘制时间或者在Java层创建和更新display list的时间。在一个View 实际被渲染前,它需要先转换为GPU能识别的格式。简单来说可能就是几个绘制命令,复杂一点,我们可能在嵌入了一条从canvas获取的自定义路径。这一步完成之后,输出结果就会被系统作为display list缓存起来。蓝色部分记录了这一帧对所有需要更新的view完成这两步花费的时间。当它很高的时候,说明有很多view突然无效(invalidate)了,或者是有几个自定义view在onDraw函数中做了特别复杂的绘制逻辑
    优化方向一:清理布局xml中并没有用到或者被设置无效(invalidate)的view组件,减少布局嵌套层级
  2. 红色部分代表执行时间,也就是Android 2D渲染引擎(OpenGL)执行display list的时间。为了将变化绘制在屏幕上,Android需要使用OpenGL ES API来绘制这些display list信息,OpenGL最终将数据传给了GPU,然后GPU渲染到屏幕上。View越复杂,OpenGL绘制所需要的命令也越复杂。如果红色这一段比较高,复杂的view都可能是罪魁祸首。还有值得注意的是比较大的峰值,这说明有些view重复提交了,也就是绘制了多次,而它们可能并不需要重绘
    优化方向二:采用局部更新view策略
  3. 橙色部分代表处理时间,更进一步,就是CPU告诉GPU渲染已经完成的时间。这部分是阻塞的,CPU会等待GPU知道确认收到了命令,如果这里比较高,说明GPU做的任务太多了,通常是由于很多复杂的view绘制从而需要过多的OpenGL渲染命令去处理

看下面这张渲染耗时图柱,都破了屏幕了,底部那条红线就没放眼里蛤!
新增数据卡顿上下滑动不了

开启渲染耗时图柱开关

一般都在开发者选项-GPU呈现模式分析:
请添加图片描述

设定优化目标为京东首页在同一机型上的交互表现

京东首页交互流畅度如下:
请添加图片描述

分以下阶段进行解析当前问题的症结点

  1. 当前的设计是否满足交互流畅度。流畅度是否能达到京东首页的体感?设计数据只加载文字;加载文字后再加载静态图片;测试验证当前布局、数据逻辑加载的交互体感情况。如不满足那基本就能确定是布局和数据加载逻辑有缺陷,则需要进行重构或重写
  2. 在第1条满足的基础上,测试同一个网络图片加载到所以列表子项里展示。记录交互体感和京东首页进行对比分析
  3. 测试单列动态图片加载效果并记录
  4. 再次测试双列动态图片加载效果并记录

=================================请看下一章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/120976.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

支持向量机 (SVM):初学者指南

照片由 Unsplash上的 vackground.com提供 一、说明 SVM&#xff08;支持向量机&#xff09;简单而优雅用于分类和回归的监督机器学习方法。该算法试图找到一个超平面&#xff0c;将数据分为不同的类&#xff0c;并具有尽可能最大的边距。本篇我们将介绍如果最大边距不存在的时候…

Failed to connect to github.com port 443:connection timed out

解决办法&#xff1a; 步骤1&#xff1a; 在这里插入图片描述 步骤2&#xff1a; -步骤3 &#xff1a;在git终端中执行如下命令&#xff1a; git config --global http.proxy http:ip:port git config --global https.proxy http:ip:port git config --global http.proxy htt…

重磅发布 OpenAI 推出用户自定义版 ChatGPT

文章目录 重磅发布 OpenAI 推出用户自定义版 ChatGPT个人简介 重磅发布 OpenAI 推出用户自定义版 ChatGPT OpenAI 首届开发者大会 (OpenAI DevDay) 于北京时间 11 月 7 日凌晨 02:00 开始&#xff0c;大会上宣布了一系列平台更新。其中一个重要更新是用户可以创建他们自己的自定…

智慧农业:农林牧数据可视化监控平台

数字农业是一种现代农业方式&#xff0c;它将信息作为农业生产的重要元素&#xff0c;并利用现代信息技术进行农业生产过程的实时可视化、数字化设计和信息化管理。能将信息技术与农业生产的各个环节有机融合&#xff0c;对于改造传统农业和改变农业生产方式具有重要意义。 图扑…

SysML理论知识

概述 由来 长期以来系统工程师使用的建模语言、工具和技术种类很多&#xff0c;如行为图、IDEF0、N2图等&#xff0c;这些建模方法使用的符号和语义不同&#xff0c;彼此之间不能互操作和重用。系统工程正是由于缺乏一种强壮的标准的建模语言&#xff0c;从而限制系统工程师和…

Makefile 介绍

目录 一、Makefile 的规则 二、一个示例 三、make 是如何工作的 四、makefile 中使用变量 五、让 make 自动推导 六、另类风格的 makefile 七、清空目标文件的规则 make 命令执行时&#xff0c;需要一个 Makefile 文件&#xff0c;以告诉 make 命令需要怎么样的去编译和…

用Python实现朴素贝叶斯垃圾邮箱分类

一、实验目的 通过本实验&#xff0c;旨在使用朴素贝叶斯算法实现垃圾邮箱分类&#xff0c;并能够理解并掌握以下内容&#xff1a; 了解朴素贝叶斯算法的基本原理和应用场景。 学习如何对文本数据进行预处理&#xff0c;包括去除标点符号、转换为小写字母、分词等操作。 理解特…

git 生成公钥

1、通过命令 ssh-keygen 生成 SSH Key&#xff1a; ssh-keygen -t ed25519 -C "Gitee SSH Key" 三次回车 2、查看生成的 SSH 公钥和私钥&#xff1a; ls ~/.ssh/ 3、把公钥设置到git id_ed25519.pub 4、测试 ssh -T gitgitee.com 成功&#xff01;&#xff01;&…

Hive3 on Spark3配置

1、软件环境 1.1 大数据组件环境 大数据组件版本Hive3.1.2Sparkspark-3.0.0-bin-hadoop3.2 1.2 操作系统环境 OS版本MacOSMonterey 12.1Linux - CentOS7.6 2、大数据组件搭建 2.1 Hive环境搭建 1&#xff09;Hive on Spark说明 Hive引擎包括&#xff1a;默认 mr、spark、…

从vue源码中看diff算法

一、v-for必须要指定key&#xff0c;其作用是什么&#xff1f; 在源码中有一个函数为&#xff0c;其中就是通过判断两个vnode的type和key进行判断&#xff0c;如果这两个属性相同&#xff0c;那么这两个vnode就是相同&#xff0c;所以在设置key的时候也不可以设置为object等无…

Fortigate SSL VPN路径遍历漏洞(CVE-2018-13379)

Fortigate SSL VPN路径遍历漏洞&#xff08;CVE-2018-13379&#xff09; 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: body"FortiToken clock drift detected" 漏洞复现1. 访问链接查看是否存在漏洞2. 查看用户名密码3. 登录后台 免责声明 仅用于技术交流,目的是…

Spring Cloud - 手写 Gateway 源码,实现自定义局部 FilterFactory

目录 一、FilterFactory 分析 1.1、前置知识 1.2、分析源码 1.2.1、整体分析 1.2.2、源码分析 1.3、手写源码 1.3.1、基础框架 1.3.2、实现自定义局部过滤器 1.3.3、加参数的自定义局部过滤器器 一、FilterFactory 分析 1.1、前置知识 前面的学习我们知道&#xff0c…

OpenAI开源全新解码器,极大提升Stable Diffusion性能

在11月7日OpenAI的首届开发者大会上&#xff0c;除了推出一系列重磅产品之外&#xff0c;还开源了两款产品&#xff0c;全新解码器Consistency Decoder&#xff08;一致性解码器&#xff09;和最新语音识别模型Whisper v3。 据悉&#xff0c;Consistency Decoder可以替代Stabl…

CROS错误 403 preflight 预检

预检 403 响应 Response for preflight 403 forbidden 如上图&#xff0c;配置了请求接口一直报错&#xff0c;前端看了没有什么问题&#xff0c;不知道哪里报错了&#xff0c;那么可能是后端没有设置跨域。&#xff08;或者是设置了&#xff0c;但是可能需要换一种方式&#…

基于springboot实现致远汽车租赁平台管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现致远汽车租赁平台管理系统演示 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统…

mysql 全文检索 demo

mysql5.6.7之后开始支持中文全文检索一直没用过&#xff0c;这次试试。 创建表 CREATE TABLE articles (id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,title VARCHAR (200),body TEXT,FULLTEXT (title, body) WITH PARSER ngram ) ENGINE INNODB DEFAULT CHARSETut…

【配置】如何在打包Spring Boot项目时按需使用日常、测试、预发、正式环境的配置文件

文章目录 前言1. 创建5个配置文件2. 在pom.xml文件中如下配置3. 在application.properties中加入环境变量 前言 在我们开发项目的时候&#xff0c;一般有四套环境&#xff1a;日常、测试、预发、正式。日常环境作为我们开发环境&#xff1b;测试环境给测试同学测试功能&#x…

Jenkins 部署.net core 项目 - NU1301错误

/root/.jenkins/workspace/householdess/services/host/fdbatt.monitor.HttpApi.Host/fdbatt.monitor.HttpApi.Host.csproj : error NU1301: 本地源“/root/.jenkins/workspace/householdess/​http:/x.x.x.x:9081/repository/nuget.org-proxy/index.json”不存在。 [/root/.je…

【Java 进阶篇】Java Filter 快速入门

欢迎来到这篇有关 Java Filter 的快速入门指南&#xff01;如果你是一名 Java 开发者或者正在学习 Java Web 开发&#xff0c;Filter 是一个强大的工具&#xff0c;可以帮助你管理和控制 Web 应用程序中的请求和响应。本文将向你解释 Filter 的基本概念&#xff0c;如何创建和配…

SHAP 和 LIME 解释模型

内容大纲 1、SHAP 解释器1.1 案例&#xff1a;用于预测患者肺癌1.2 案例中使用的shap解释器1.3 SHAP工作原理1.4 举例说明 2、LIME 解释器2.1 案例&#xff1a;判断法律案件胜诉可能性2.2 LIME解释器工作原理2.3 本地解释模型的训练过程2.4 举例说明1&#xff1a;新闻分类2.4 举…