安卓进阶(一)App性能优化

文章目录

  • 性能优化的目的及方向
    • 流畅性
      • 启动速度
      • 页面显示速度
      • 响应速度
    • 稳定性
      • ANR
      • Crash
    • 资源节省性
  • 布局优化
    • 选择耗费性能较少的布局
    • 减少布局的层级(嵌套)
    • 使用布局标签
      • 尽量少用布局属性wrap_content
      • include
      • merge
      • include与merge的区别
      • ViewStub
  • 内存泄露
    • 常见内存泄露原因
      • 集合类添加元素
      • Static关键字修饰成员
      • 非静态内部类 / 匿名类
      • 资源对象使用后未关闭
  • 内存优化

性能优化的目的及方向

性能优化的目的是为了让应用程序App 更快、更稳定 & 更省。具体介绍如下:

  • 更快:应用程序 运行得更加流畅、不卡顿,能快速响应用户操作
  • 更稳定:应用程序 能 稳定运行 & 解决用户需求,在用户使用过程中不出现应用程序崩溃(Crash) 和 无响应(ANR)的问题
  • 更省:节省耗费的资源,包括 内存占有、电池量、网络资源等

针对上述目的,APP优化的指标就是:流畅性、稳定性、资源节省性。

具体实现如下:

在这里插入图片描述

流畅性

减少使用中的卡顿、响应时间久等问题,给用户一个操作流畅的体验,主要针对3个方面进行优化:

  • 启动速度
  • 页面显示速度
  • 响应速度

启动速度

优化原因:初次加载应用,需要加载很多资源或者逻辑功能。

优化方案:采用异步加载(多线程)、分步加载、延期加载等策略,减少启动应用时的加载任务,从而提高启动速度。

页面显示速度

优化原因:页面需绘制的内容(布局或控件)太多,导致页面测量时间太长;页面绘制效率过低,导致绘制时间过长。

优化方案:布局优化与绘制优化

响应速度

优化原因:应用程序出现 ANR 情况,从而导致 应用程序响应速度慢

优化方案:使用多线程,将大量耗时操作放在工作线程中执行。

优化方案:使用多线程,将大量耗时操作放在工作线程中执行,比如AsyncTask,HandlerThread等等

稳定性

影响Android 应用稳定性的原因有很多,主要是:应用崩溃(Crash)、应用无响应(ANR)

ANR

程序出现ANR(Application Not Responding,应用程序无响应),导致应用程序响应慢或者屏幕卡死在一个页面。

常见的ANR原因:

  • 应用在5s内未响应用户输入的事件(按键或触摸)。
  • 广播接收器(BroadcastReceiver)在10s内未完成相关事件的处理。
  • 服务(Service)在20s内无法处理完成。

优化方案:使用多线程,将大量耗时操作放在工作线程中执行,比如AsyncTask,HandlerThread等等

实际开发中,当一个进程发生了ANR,系统会在 /data/anr目录下创建一个文件 traces.txt,通过分析该文件可定位出ANR的原因

Crash

程序出现Crash(崩溃)很多情况是因为内存溢出即OOM。

Android系统为每个应用程序分配的内存有限,当应用程序中出现内存泄露较多,不正常使用内存等情况时,容易导致应用程序出现所需的内存超出系统能够为其分配的内存限额(OOM),从而导致程序崩溃。

解决Crash就是解决OOM,涉及到的工作就是内存优化。

资源节省性

优化原因:由于移动设备的硬件性能有限,故减少应用程序的资源消耗显得十分重要

优化方向:内存大小、安装包大小、耗电量 & 网络流量

主要手段包含:内存优化、减少安装包大小、减少网络流量、减少应用耗电量。
在这里插入图片描述

布局优化

布局性能的好坏主要影响Android中页面显示速度,布局影响性能的实质在于:页面的测量与绘制时间

选择耗费性能较少的布局

  • 耗费低的布局 = 功能简单 = FrameLayout、LinearLayout
  • 耗费高的布局 = 功能复杂 =RelativeLayout

减少布局的层级(嵌套)

  • 原理:布局层级少 ->> 绘制的工作量少 ->> 绘制速度快 ->> 性能提高
  • 优化方式:使用布局标签 & 合适选择布局类型

注意:宁愿选择1个耗费性能高的布局,也不采用嵌套多个耗费性能低的布局

使用布局标签

尽量少用布局属性wrap_content

布局属性wrap_content 会增加布局测量时计算成本,应尽可能少用;特别是在已知宽高为固定值时,不使用wrap_content。

include

include>标签可以实现在一个layout中引用另一个layout的布局,这通常适合于界面布局复杂、不同界面有共用布局的APP中,比如一个APP的顶部布局、侧边栏布局、底部Tab栏布局、ListView和GridView每一项的布局等,将这些同一个APP中有多个界面用到的布局抽取出来再通过<include>标签引用,既可以降低layout的复杂度,又可以做到布局重用(布局有改动时只需要修改一个地方就可以了)。

merge

merge标签是用来帮助在视图树中减少重复布局的,当一个layout包含另外一个layout时。
merge使用的要点:

  • merge必须放在布局文件的根节点上
  • merge并不是一个ViewGroup,也不是一个View,它相当于声明了一些视图,等待被添加。
  • merge标签被添加到A容器下,那么merge下的所有视图将被添加到A容器下。
  • 因为merge不是View,所有它没法设置标签属性,或者说设置了是无效的。
  • 因为merge标签并不是View,所以在LayoutInflate.inflate方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为true,也就是必须为merge下的视图指定一个父亲节点。

实例:
不使用merge:
layout1.xml

<FrameLayout>
   <include layout="@layout/layout2"/>
</FrameLayout>

layout2.xml

<FrameLayout>
   <TextView />
</FrameLayout>

实际效果:

<FrameLayout>
   <FrameLayout>
      <TextView />
   </FrameLayout>
</FrameLayout>

使用merge:
layout1.xml

<FrameLayout>
   <include layout="@layout/layout2"/>
</FrameLayout>

layout2.xml

<merge>
   <TextView />
</merge>

实际效果:

<FrameLayout>
   <TextView />
</FrameLayout>

include与merge的区别

从上边的例子中可以看到,include实际上是将另外一个layout完整的嵌入到需要使用的地方。由于所有的组件都必须在ViewGroup中,这就导致了,使用include标签,嵌入时,会多一层ViewGroup,而使用merge则相当于声明了一个虚拟的ViewGroup,使得在include时它可以完全融入merge到需要使用的地方。

ViewStub

ViewStup是一个轻量级的view,之所以说它是轻量级的view是因为它在页面加载渲染的过程中不会去绘制,只是在你需要的时候再去绘制。

ViewStub标签的作用是用于懒加载布局,当系统碰到ViewStub标签的时候是不进行绘制处理(如measure、layout等),比设置View隐藏、不可见更高效。

使用ViewStub的好处:

  • 可以避免ViewStub所对应的视图measure、layout等性能消耗,只有在使用时才会执行,例如在APP启动时提升页面显示速度。
  • 对比invisible和gone的用法,当设置为invisible,view对象会占用位置,只是状态不可见,对象还是会被创建、初始化、占用资源。如果设置为gone,view在layout布局文件中不占用位置,但对象还是会被创建、初始化、占用资源。

ViewStub的缺点在于不可使用<merge>标签,它在使用上类似于<include>标签

内存泄露

从机制上讲:Java存在GC,理应不存在内存泄露,出现内存泄露的原因仅仅是外部人为原因,无意识地持有对象引用,使得持有引用者的生命周期 > 被引用者的生命周期

常见内存泄露原因

集合类添加元素

内存泄露原因:集合类 添加元素后,仍引用着 集合元素对象,导致该集合元素对象不可被回收,从而 导致内存泄漏

// 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
List<Object> objectList = new ArrayList<>();        
       for (int i = 0; i < 10; i++) {
            Object o = new Object();
            objectList.add(o);
            o = null;
        }
// 虽释放了集合元素引用的本身:o=null)
// 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象

解决方案:
由于1个集合中有许多元素,故最简单的方法 = 清空集合对象 & 设置为null

// 释放objectList
objectList.clear();
objectList=null;

Static关键字修饰成员

被 Static 关键字修饰的成员变量的生命周期 = 应用程序的生命周期.

泄露原因:被 Static 关键字修饰的成员变量 引用耗费资源过多的实例(如Context),则容易出现该成员变量的生命周期 > 引用实例生命周期的情况,当引用实例需结束生命周期销毁时,会因静态变量的持有而无法被回收,从而出现内存泄露

public class ClassName {
 // 定义1个静态变量
 private static Context mContext;
 //...
// 引用的是Activity的context
 mContext = context; 

// 当Activity需销毁时,由于mContext = 静态 & 生命周期 = 应用程序的生命周期,故 Activity无法被回收,从而出现内存泄露
}

解决方案:

  1. 尽量避免 Static 成员变量引用资源耗费过多的实例(如 Context)。
  2. 使用 弱引用(WeakReference) 代替 强引用 持有实例

非静态内部类 / 匿名类

非静态内部类持有外部类的引用,导致外部类无法被释放。

常见情况有:

  • 非静态内部类中创建静态的实例
  • 多线程:AsyncTask等,当工作线程正在处理任务,它持有外部类的引用,导致外部类无法被GC
  • 消息传递机制:Handler,Handler类持有外部activity的引用,当消息队列中还有未处理的消息时,消息队列中的
    Message持有Handler实例的引用。这种引用依赖关系,导致Activity无法被销毁。

在这里插入图片描述

资源对象使用后未关闭

泄露原因:对于资源的使用(如广播、文件流、数据库操作的游标、图片资源BitMap),若在Activity销毁时,没有及时关闭或注销这些资源,从而导致内存泄露。

解决方案:
在Activity销毁时:及时关闭 / 注销资源

内存优化

在这里插入图片描述

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

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

相关文章

前沿技术|人工智能的崛起和发展历程

前言&#xff1a; 人工智能的作用是使计算机能够模仿人类智能和学习能力&#xff0c;从而实现自动化、智能化和优化决策的目标。 文章目录 人工智能背景介绍发展状态未来展望 总结 人工智能 背景 人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;的产生…

多模态大模型综述: LLaVA, MiniGPT4

文章目录 LLaVA一. 简介1.1. 摘要1.2. 引言 二. 相关工作三. 基于GPT辅助的视觉指令数据生成四. Visual Instruction Tuning4.1 网络结构4.2 训练 LLaVA 一. 简介 题目: Visual Instruction Tuning 机构&#xff1a;微软 论文: https://arxiv.org/pdf/2304.08485.pdf 代码&am…

大数据大作业(课程设计)

题目&#xff1a;信息爬取字数统计及可视化 内容及要求&#xff1a; 配置Hadoop平台&#xff1b;利用爬虫技术爬取任一门户网站新闻栏目一定时间段内的新闻信息&#xff0c;保存为一个或多个文件并上传到Hadoop平台以本人学号命名的文件夹下&#xff1b;利用MapReduce框架编程完…

【java】JDK21 要来了

文章目录 前言更丝滑的并发编程模式虚拟线程&#xff08;Virtual Threads&#xff09;结构化并发&#xff08;Structured Concurrency&#xff09;作用域值&#xff08;Scoped Values&#xff09; 试验一下虚拟线程的例子结构化编程的例子Scoped Values 的例子 前言 不过多久&…

大数据分析案例-基于LightGBM算法构建航空公司满意度预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Nexus搭建Maven私有库介绍

为什么需要Maven私有库&#xff1f; 使用Maven获取Java依赖包的时候&#xff0c; 默认是从Maven的中央库下载 jar文件&#xff0c; 中央库的地址是&#xff1a; https://repo.maven.apache.org/maven2 。 如果下载速度慢&#xff0c; 可以使用阿里的镜像&#xff0c; 地址如下…

【服务器数据恢复】HP LeftHand存储raid5不可用的数据恢复案例

HP LeftHand存储简介&#xff1a; HP LeftHand存储支持搭建RAID5、RAID6、RAID10磁盘阵列&#xff0c;支持卷快照&#xff0c;卷动态扩容等。服务端和客户端分别如下&#xff1a; LeftHand存储共有三个级别&#xff1a;物理磁盘、基于多个物理磁盘组成的逻辑磁盘&#xff08;ra…

浏览器渲染流程

解析HTML&#xff0c;生成DOM树&#xff0c;解析CSS&#xff0c;生成CSSOM树 将DOM树和CSSOM树结合&#xff0c;生成渲染树(Render Tree) Layout(回流):根据生成的渲染树&#xff0c;进行回流(Layout)&#xff0c;得到节点的几何信息&#xff08;位置&#xff0c;大小&#x…

Selenium+Pytest自动化测试框架实战

前言 Selenium和Pytest是非常流行的自动化测试框架&#xff0c;二者的配合可以有效地进行Web应用程序的测试。在使用Selenium和Pytest进行自动化测试时&#xff0c;可以实现自动化测试的模块化、重复使用&#xff0c;并且可以在现有的测试项目中方便地集成和调用。 测试框架简…

B树和B+树索引

B树索引 磁盘IO读数据到内存 malloc/new 向 kernel申请4B空间&#xff0c;实际系统可能给2个页面空间即8KB&#xff0c;剩下8KB-4B空间由 lib.so 或libc.so 的 ptmalloc 或tcmalloc管理 。这样就不需要每次去kernel申请内存 磁盘IO同理&#xff0c;我们读一部分数据会把一整…

学了Python后还用学R语言吗?

学习R语言是否有必要取决于你的具体需求和背景。虽然R语言和Python都是数据科学领域广泛使用的编程语言&#xff0c;但它们之间还是存在一些差异。 如果你主要从事数据分析、统计建模或者数据可视化等工作&#xff0c;那么学习R语言可能更为适合。R语言在数据处理和统计分析方…

02_类加载子系统

02_类加载子系统 一、内存结构概述二、类加载器与类的加载过程1、类加载器子系统的作用2、类加载器ClassLoader的作用3、类的加载过程 三、类加载器的分类1、启动类加载器2、扩展类加载器3、应用程序类加载器4、自定义类加载器5、获取ClassLoader的几种方式 五、双亲委派机制1、…

浅谈.NET语言开发应用领域

.NET语言是一种跨平台的开发框架&#xff0c;适用于各种应用程序的开发。以下是一些常见的.NET语言开发应用领域&#xff1a; 桌面应用程序开发&#xff1a;使用.NET框架开发的桌面应用程序可以在Windows操作系统上运行&#xff0c;包括Windows Forms和WPF。这些应用程序可以用…

第二章 进程的描述与控制

目录 一、进程的概念、组成、特征 1.1 进程的概念 1.1.1 程序 1.1.2 进程 1.2 进程的组成 1.3 进程控制块PCB 1.4 进程的特征 二、进程的状态与转换 2.1 进程的状态 2.2 创建态、就绪态 2.3 运行态 2.4 阻塞态 2.5 终止态 2.6 进程状态的转换 2.7 进程的组织 三…

【状态估计】无迹卡尔曼滤波(UKF)应用于FitzHugh-Nagumo神经元动力学研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【ProNoC】Chap.1 ProNoC生成2x2的mesh型的4核片上网络系统;实现NoC的RTL设计

【ProNoC】Chap.1 ProNoC生成2x2的mesh型的4核片上网络系统&#xff1b;实现NoC的RTL设计 0. NoC多核片上网络生成器ProNoCProNoC的功能实现 1. 生成一个叫做Mor1kx SoC的单个Tile&#xff08;包含NI网络接口&#xff09;1.1 打开ProNoC用于生成Tile的GUI界面1.2 为Tile添加时钟…

团体程序设计天梯赛-练习集L1篇①

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

【Servlet学习一】认识Servlet 创建第一个Servlet项目

目录 &#x1f31f;需要知道&#xff1a; &#x1f308;1、Tomcat是什么&#xff1f; &#x1f308; 2、Maven &#x1f31f;一、认识Servlet &#x1f308;1、Servlet是什么&#xff1f; &#x1f308;2、实现第一个Servlet项目。 &#x1f308;3、简单了解Postman工具…

LTV-6314-ASEMI代理台湾光宝高速光耦LTV-6314

编辑&#xff1a;ll LTV-6314-ASEMI代理台湾光宝高速光耦LTV-6314 型号&#xff1a;LTV-6314 品牌&#xff1a;台湾光宝 封装&#xff1a;LSOP-6 引脚数量&#xff1a;6 类型&#xff1a;光耦 特性&#xff1a;台湾光宝、IGBT驱动器、储能专用光耦&#xff3c;高速光耦 …

云服务器ECS_云主机_服务器托管_弹性计算-阿里云

阿里云服务器ECS&#xff08;Elastic Compute Service&#xff09;是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云服务器网分享阿里云服务器ECS详细介…