一文高端Android性能优化-总结篇
以下从几个方面来总结一下Android的性能优化:
1:界面卡顿优化
2:内存优化
3:App启动优化
界面卡顿优化
Android的界面为每秒60帧,即必须在16ms内完成1帧的绘制,如果某个方法耗时过程,导致16ms内无法完成绘制,会导致丢帧,丢帧的多了,直观上感受就是界面卡顿。
60帧是人眼观看动画比较合适的频率,如果每秒的帧数过少,即频繁的出现丢帧,就会感觉界面的卡顿。
1:通过Traceview找出卡主主线程的地方
卡住主线程说明函数在主线程被调用的时长比较长,包括:
1)单个函数调用的时长长
2)函数被调用的次数比较多
2:使用方法:
1)Terminal打开DDMS,输入指令:Monitor
2)点击start method profiling

3)操作APP可能有问题的界面
4)再次点击stop method profiling,生成表格:

3:具体案例分析:recyclerView的onBindViewHolder,当复用屏幕外的数据是,是脏数据,会进行重新绑定,调用onBindViewHolder

@Override
publicvoid onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
Log.d(TAG, "onBindViewHolder--->" + position);
。。。。。。
。。。。。。。
SystemClock.sleep(7);
}

SystemClock.sleep(10)模拟RecyclerView滚动过程中的耗时操作,操作Recyclerview,得到以下表格:
Real Time/Call表示一个函数被调用的时长, Calls+Recursion + call totals表示一个函数被调用和被递归调用的次数

内存优化:
1:Memory Monitor:
Memory Monitor只能看个大概,可以查看内存抖动,或者内存增长的趋势,具体的小的泄漏,还得通过Heap Viewer查看
内存抖动:短时间内发生了多次内存的涨跌,意味着很有可能发生率内存抖动。
内存抖动带来的问题:短时间内的内存飙升,系统需要频繁的进行GC,而GC是需要主线程停下来,并且占用CPU资源的,会导致界面卡顿。
例子1:
publicvoid click(View view) {
for (int i = 0; i < 100; i++) {
byte[] b = newbyte[2000];
}
}
例子2:

privateint nums[][] = newint[250][250];
//内存抖动案例:
//短时间内创建大量的临时变量privatevoid init() {
Random random = new Random();
for (int i = 0; i < nums.length; i++) {
for(int j=0; j<nums[i].length; j++){
nums[i][j] = random.nextInt(1000);
}
}
}
privatevoid printNums(){String totalNums = "";for (int i = 0; i < nums.length; i++) {for(int j=0; j<nums[i].length; j++){totalNums += nums[i][j];}}}//优化:private void printNums2(){StringBuffer totalNums = new StringBuffer();for (int i = 0; i < nums.length; i++) {for(int j=0; j<nums[i].length; j++){totalNums.append(nums[i][j]);}}}使用Monitor监控:

避免内存抖动的方法:
1)尽量避免在循环体内创建对象,应该把对象创建移到循环体外
2)自定义view的onDraw会被频繁调用,避免在这个函数里面new一个新的对象
2:Heap Viewer:
监控:能够实时观测内存的变动(短时间内通过Memory Monitor是看不出来的,曲线坡度太小,内存变动值很小,定位不到具体的代码)
Heap Viewer具体定位到哪个位置内存泄漏。
内存泄漏例子:

protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//test1(); init();handler.sendEmptyMessageDelayed(0, 100000);}
//模拟当MainActivity跳转到MainActivity2的时候,// 延迟发送消息导致的内存泄漏问题private Handler handler = new Handler(){@Overridepublicvoid handleMessage(@NonNull Message msg) {super.handleMessage(msg);}};publicvoid click(){Intent intent = new Intent(this, MainActivity2.class);startActivity(intent);finish();}
首先运行应用,处在MainActivity,点击Dump Java Heap,获取当前内存的快照:

得到以下表格:

修改为根据包名查看更方便快速定位到我们自己的代码:

Leaks为0说明当前没有发生内存泄漏
MainActivity的depth为3,说明MainActivity有被引用

点击MainActivity的click,跳转到MainActivity2,MainActivity.finish(),模拟MainActivty发生内存泄漏的场景(Handler引用MainActivity导致内存泄漏),然后点击GC,再截取内存快照
Dump Java Heap:

黄色的Leaks为2说明发生了内存泄漏,点击Leaks,通过以下References可以找到MainActivity被引用的路径。

3:LeakCanary
在一个Activity执行完onDestroy后,将它放入到WeakReference中,然后将这个WeakReference类型的Activity的对象与ReferenceQueue关联,注意: 如果一个对象要被GC回收了,会把它引用的对象放入到ReferenceQueue中。这时候只需要在ReferenceQueue中去查找是否存在该对象,如果没有就执行一个GC,再次查找,如果还是没有,则说明该对象可能无法被回收,也就可能发生了内存泄漏,最后使用HAHA这个开源库取分析dump之后的heap内存
在一个Activity执行完onDestroy后,将它放入到WeakReference中,然后将这个WeakReference类型的Activity的对象与ReferenceQueue关联,注意: 如果一个对象要被GC回收了,会把它引用的对象放入到ReferenceQueue中。这时候只需要在ReferenceQueue中去查找是否存在该对象,如果没有就执行一个GC,再次查找,如果还是没有,则说明该对象可能无法被回收,也就可能发生了内存泄漏,最后使用HAHA这个开源库取分析dump之后的heap内存
在一个Activity执行完onDestroy后,将它放入到WeakReference中,然后将这个WeakReference类型的Activity的对象与ReferenceQueue关联,注意: 如果一个对象要被GC回收了,会把它引用的对象放入到ReferenceQueue中。这时候只需要在ReferenceQueue中去查找是否存在该对象,如果没有就执行一个GC,再次查找,如果还是没有,则说明该对象可能无法被回收,也就可能发生了内存泄漏,最后使用HAHA这个开源库取分析dump之后的heap内存
在一个Activity执行完onDestroy后,将它放入到WeakReference中,然后将这个WeakReference类型的Activity的对象与ReferenceQueue关联,注意: 如果一个对象要被GC回收了,会把它引用的对象放入到ReferenceQueue中。这时候只需要在ReferenceQueue中去查找是否存在该对象,如果没有就执行一个GC,再次查找,如果还是没有,则说明该对象可能无法被回收,也就可能发生了内存泄漏,最后使用HAHA这个开源库取分析dump之后的heap内存
分为两个步骤:
1)通过虚引用的ReferenceQueue,判断一个对象是否被回收:
虚引用:对于对象来说,是无感的,如果只存在虚引用,GC的时候会直接被回收。虚引用的目的是为了追踪一个对象被回收的时机。如果一个定义了虚引用的对象GC之后被回收了,这个对象会被放入RefereceQueue中,LeakCanary就是在GC之后去检测该队列中是否有该对象判断该对象是否已经被回收。
2)初步判定有内存泄漏之后,通过开源库Haha分析dump之后的heap内存,从而定位到具体的内存泄露的对象的引用链条。
APP应用启动优化
1:冷启动和热启动
1)冷启动:app没有启动过或者进程被杀死,系统不存在该app进程,此时启动为冷启动。冷启动流程就是app启动流程全过程,包括创建app进程、加载资源、启动MainThread、初始化SplashActivity并加载布局等。
2)热启动:app暂时退到了后台,热启动将它从后台重新带到前台,展示给客户。
我们要做的优化就是针对热启动
3):冷启动的函数调用过程:
Zygote Fork Proccess
-> Application:attachBaseContext()
-> Application:onCreate()
-> MainActiviity:onCreate()
2:用TraceView获取App的启动耗时,查找具体的耗时的函数进行优化:

publicclass MyApplication extends Application {
@Override
publicvoid onCreate() {
Debug.startMethodTracing("startApp");
super.onCreate();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Debug.stopMethodTracing();
}
}

在/sdcard/目录下得到一个startApp.trace文件

通过DDMS打开该文件:可以看到Application里面的onCreate里的哪些代码进行了耗时操作:

3:解决方案:
1)将启动页主题背景设置成闪屏页图片
这么做的目的主要是为了消除启动时的黑白屏,给用户一种秒响应的感觉,但是并不会真正减少用户启动时间,仅属于视觉优化。
2)第三方工具的初始化一般都在Application的onCreate里面执行,会造成大量的耗时,解决方案:
a:放在子线程中加载不影响业务的情况,则优先选择放在子线程中加载
b:第三方工具的懒加载初始化,即用到的时候再进行初始化
更多性能优化知识点:点击这里

相关文章:
一文高端Android性能优化-总结篇
以下从几个方面来总结一下Android的性能优化:1:界面卡顿优化2:内存优化3:App启动优化界面卡顿优化Android的界面为每秒60帧,即必须在16ms内完成1帧的绘制,如果某个方法耗时过程,导致16ms内无法完…...
深入讲解CFS组调度!(上)
注:本文缩写说明 一、CFS组调度简介 1.1. 存在的原因 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢,比如多用户计算机系统每个用户的所有任务划分到一个分组中,A用户90个相同任务,而B…...
大数据实操项目分享:餐饮智能推荐服务在线实习项目
项目背景:在“互联网"背景下,餐饮企业的经营方式发生了很大的变革:团购和020拓宽了销售 渠道,电子点餐、店内WIFI等信息技术提升了服务水平,大数据、私人定制更好地满足了细分市场的需求等。但是与此同时…...
代码随想录day38
动态规划五部曲 确定dp数组以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 509. 斐波那契数 https://leetcode.cn/problems/fibonacci-number/ class Solution {public int fib(int n) {if(n0) return 0;if(n<3) return 1;int[] dp new int[n]…...
《计算机网络:自顶向下方法》实验5:TCP
Q1 包含HTTP POST消息的TCP报文段的序号是多少?注意:为了发现POST 命令, 你需要在wireshark底部的报文内容域窗口中去查找,查找数据中包含 “POST”的段。 如图所示,由报文中的POST 和 HTTP/1.1可知,其包含HTTP POST消息; TCP报文段的序号可见TCP报文: Sequence Number:…...
【踩坑指南】Stable Diffusion 服务器端部署笔记
文章目录下载github文件配置环境ckpt文件权重下载生成图像NSFW检查(瑟图过滤)下载github文件 https://github.com/CompVis/stable-diffusion 这个网址,下载压缩包解压,也可以用git clone下载 配置环境 这一步坑最多,…...
[qiankun]-多页签缓存
[qiankun]-多页签缓存环境功能需求多页签缓存方案方案1.主服务进行html替换方案2.微服务vnode 替换方案3.每个微服务都不卸载微服务加载方式的选择微服务的路由路径选择微服务的缓存工具微服务的容器使用tab作为微服务的挂载容器使用微服务路由作为微服务的挂载容器场景描述微服…...
2|电子技术|数字电子技术基础|雨课堂习题|考前回顾
A/DD/A转化横向与阵列 相乘,竖向为或阵列 相加!功率放大电路克服交越失真,是在乙类的基础上增加两个二极管,使微导通,使三极管导通时间大于半个周期,小于一个周期,构成甲乙类工作状态。选择填空…...
vue+echarts:圆形柱状图设置角度和最大值
第020个点击查看专栏目录本示例是显示圆形的柱状图,angleAxis设置一个max, angleAxis上startAngle:90 , 将0点设置为最顶点。 文章目录示例效果示例源代码(共100行)相关资料参考专栏介绍示例效果 示例源代码…...
Linux系统安装Nginx常见报错问题
安装Nginx从nginx官网下载所需版本的nginx,http://nginx.org/下载之后,将安装包上传到linux系统指定路径解压文件,tar -zxvf nginx-1.22.1.tar.gz (此处用1.22.1版本为例)进入安装包目录,cd nginx-1.22.1执…...
按下按键之后,打印一句话------>三个按键需要实现
main.c: #include "key.h" extern void printf(const char *fmt, ...); void delay_ms(int ms){ int i,j; for(i 0; i < ms;i) for (j 0; j < 1800; j);} int main(){ //key1键盘 //EXIT控制器初始化 void PF9_exti_init(); //GICD控…...
Mac配置VScode
Mac配置VScode 常用技巧 命令调色板 根据您当前的上下文访问所有可用的命令。 键盘快捷键:⇧⌘P 快速打开 快速打开文件。 键盘快捷键:⌘P **提示:**类型?查看命令建议。 在最近打开的文件夹和工作区之间导航 最近打开 键盘快捷…...
MAC地址IP地址 端口
网络结构: 服务器-客户机(C/S)Client-Server结构,如QQ,LOL都拥有客户端 优点:响应速度快,形式多样,安全新较高缺点:安装软件和维护,不能跨平台LINUX/windows/MAC浏览器-…...
关于虚拟数字人你想知道的都在这里
2022年底,微软旗下的人工智能实验室Open AI发布的对话式大型语言模型ChatGPT聊天机器人一夜蹿红,5天用户量超百万,在各大中外媒体平台掀起了一阵热潮。也带火了人工智能相关产业,AI虚拟数字人就是其中之一,一个随着元宇…...
分布式任务调度处理方案(无代码)
业务涉及到,需要向数据库、redis、elasticsearch、MinIO写四份数据,这里存在分布式事务问题。如何解决问题,先分析cap,是要保证可用性,还是保证一致性。如何选择是CP还是AP?分析业务场景CP的场景࿱…...
2023年博管办香江学者计划、澳门青年学者开始申报
2023年2月20日,全国博士后管委会办公室官方网站发出了2023年香江学者计划、澳门青年学者计划和博士后国(境)外学术交流项目申报指南,以下知识人网小编仅转载香江学者计划和澳门青年学者计划申报指南并做重点解读。知识人网整理香江…...
(二十一)、实现评论功能(1)【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】
1,评论回复模块的样式布局 1.1 在detail页面添加uview中的 Empty 内容为空组件 <!-- 评论区 --><view class"comment"><u-empty mode"comment" icon"http://cdn.uviewui.com/uview/empty/comment.png"></u-emp…...
【Docker】初识Dcoker以及镜像操作(一)
目录 1.初识Docker 1.1.什么是Docker 1.1.1.应用部署的环境问题 1.1.2.Docker解决依赖兼容问题 1.1.3.Docker解决操作系统环境差异 1.1.4.小结 1.2.Docker和虚拟机的区别 1.3.Docker架构 1.3.1.镜像和容器 1.3.2.DockerHub 1.3.3.Docker架构 1.3.4.小结 1.4.安装D…...
(1)C#传智:在vs2022中基本了解(第一天)
开始vs2022中C#入门,就是一笔记,算不上原创,没办法得选啊。 一、vs中卸载项目和移除项目有什么区别? 1、卸载、移除都不会移除物理文件,只会删除关联 2、卸载删除关联的程度低,卸载后项目只是“变灰色…...
【数据结构与算法】算法的时间复杂度和空间复杂度
文章目录前言1.算法效率1.1.如何衡量一个算法的好坏1.2.算法的复杂度2.时间复杂度2.1.时间复杂度的概念2.2.大O的渐进表示法2.3.常见时间复杂度计算举例2.4.常见时间复杂度3.空间复杂度4.复杂度oj练习Practice.1 消失的数字Practice.2 旋转数组写在最后前言 关于时空复杂度的分…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
