Android 面试题 重点---性能篇章

本文详细介绍了Android系统的性能优化,包括布局优化(如减少层级、使用ViewStub和避免过度绘制)、启动优化、内存分析工具的使用、常见内存泄漏场景及对策、内存空间优化、稳定性优化、线程优化、响应时间优化以及内存和CPU耗电优化。提出了减少对象创建、使用内存缓存、避免主线程耗时操作等具体措施。
摘要由CSDN通过智能技术生成

1 布局优化

2 启动优化

3 内存分析工具

4 常见内存泄漏场景

5 优化内存空间

6 稳定性优化

7 线程优化

8 响应时间优化

9 内存优化-(cpu 耗电)

Android系统的 性能优化目的 及一些案例 ?

1 布局优化

关于布局优化的思想很简单,就是尽量减少布局文件的层级。减少测量和绘制时间、提高复用性 这个道理很浅显,布局中的层级少了,就意味着Android绘制时的工作量少了,那么程序的性能自然就提高了。

减少层级:合理使用RelativeLayout和LinerLayout,合理使用Merge。

提高显示速度:使用ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。

布局复用:可以通过标签(include)来提高复用。

尽可能少用 wrap_content:wrap_content 会增加布局measure时计算成本,在已知宽高为固定值时,不用wrap_content。

其他:删除控件中无用的属性。其次有选择地使用性能比较低的ViewGroup。

如何进行布局优化?

关于有选择地使用性能比较低的ViewGroup,这就需要我们开发就实际灵活选择了。

例如:如果布局中既可以使用LinearLayout也可以使用RelativeLayout,那么就采用LinearLayout,这是因为RelativeLayout的功能比较复杂,它的布局过程需要花费更多的CPU时间。FrameLayout和LinearLayout一样都是一种简单高效的ViewGroup,因此可以考虑使用它们,但是很多时候单纯通过一个LinearLayout或者FrameLayout无法实现产品效果,需要通过嵌套的方式来完成。这种情况下还是建议采用RelativeLayout,因为ViewGroup的嵌套就相当于增加了布局的层级,同样会降低程序的性能。

(1)避免过度绘制

过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的UI结构中,如果不可见的UI也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的CPU以及GPU源。

如何避免过度绘制呢,如下:

布局上的优化:移除XML中非必须的背景,移除Window默认的背景、按需显示占位背景图片。

自定义View优化:使用 canvas.clipRect() 来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。

绘制优化

绘制优化是指View的onDraw方法要避免执行大量的操作,这主要体现在两个方面:

①onDraw中不要创建新的局部对象。

因为onDraw方法可能会被频繁调用,这样就会在一瞬间产生大量的临时对象,这不仅占用了过多的内存而且还会导致系统更加频繁gc,降低了程序的执行效率。

②onDraw方法中不要做耗时的任务,也不能执行成千上万次的循环操作,尽管每次循环都很轻量级,但是大量的循环仍然十分抢占CPU的时间片,这会造成View的绘制过程不流畅。

2 启动优化

通过对启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提高应用的启动速度。启动主要完

成件事:UI布局、绘制和数据准备。因此启动速度优化就是需要优化这三个过程:

UI布局:应用一般都有闪屏页,优化闪屏页的UI布局,可以通过 Profile GPU Rendering 检测丢帧情况。

启动加载逻辑优化:可以采用分布加载、异步加载、延期加载策略来提高应用启动速度。

数据准备:数据初始化分析,加载数据可以考虑用线程初始化等策略。

3 内存分析工具

做内存优化前,需要了解当前应用的内存使用现状,通过现状去分析哪些数据类型有问题,各种类型的分布情况如何,以及在发现问题后如何发现是哪些具体对象导致的,这就需要相关工具来帮助我们。

(1)Memory Monitor

Memory Monitor是一款使用非常简单的图形化工具,可以很好地监控系统或应用的内存使用情况,主要有以下功能:

  • 显示可用和已用内存,并且以时间为维度实时反应内存分配和回收情况。

  • 快速判断应用程序的运行缓慢是否由于过度的内存回收导致。

  • 快速判断应用是否由于内存不足导致程序崩溃。

4 常见内存泄漏场景

  • 常见内存泄漏场景:(也属于稳定性)

  • 资源性对象未关闭。比如Cursor、File文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。

  • 注册对象未注销。比如事件注册后未注销,会导致观察者,列表中、维持着对象的引用。

  • 类的静态变量持有大数据对象。

  • 非静态内部类的静态实例。

  • Handler临时性内存泄漏。如果Handler是非静态的,容易导致 Activity 或 Service 不会被回收。

  • 容器中的对象没清理造成的内存泄漏。

  • WebView。WebView 存在着内存泄漏的问题,在应用中只要使用一次 WebView,内存就不会被释放掉。

****除此之外,内存泄漏可监控,常见的就是用LeakCanary第三方库,这是一个检测内存泄漏的开源库,使用非常简单,可以在发生内存泄漏时告警,并且生成 leak(显示包路径) 分析泄漏位置,同时可以提供 Dump 文件进行分析。

5 优化内存空间

没有内存泄漏,并不意味着内存就不需要优化,在移动设备上,由于物理设备的存储空间有限,Android 系统对每个应用进程也都分配了有限的堆内存,因此使用最小内存对象或者资源可以减小内存开销,同时让GC 能更高效地回收不再需要使用的对象,让应用堆内存保持充足的可用内存,使应用更稳定高效地运行。常见做法如下:

  • 对象引用:强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。

  • 减少不必要的内存开销:注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。

  • 使用最优的数据类型:比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。

  • 图片内存优化:可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。

(1)避免创建过多的对象

(2)不要过多的使用枚举类型,枚举占用的内存空间比整型要大

(3)常量请使用static final来修饰

(4)适当的使用软引用和弱引用

(5)采用内存缓存和磁盘缓存

(6)尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏的问题

性能分析工具:

Profile GPU Rendering GPU

在手机开发者模式下,有一个卡顿检测工具叫做:Profile GPU Rendering

一个图形监测工具,能实时反应当前绘制的耗时

6 稳定性优化:

Android 应用的稳定性定义很宽泛,影响稳定性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性造成影响。其中最常见的两个场景是:Crash 和 ANR,这两个错误将会使得程序无法使用,比较常用的解决方式如下:

  • 提高代码质量。比如开发期间的代码审核,看些代码设计逻辑,业务合理性等。

  • 代码静态扫描工具。常见工具有Android Lint、Check style、PMD等等。

  • Crash监控。把一些崩溃的信息,异常信息及时地记录下来,以便后续分析解决。

  • Crash上传机制。在Crash后,尽量先保存日志到本地,然后等下一次网络正常时再上传日志信息。

7 线程优化:

线程优化的思想是采用线程池:

1 避免程序中存在大量的Thread。线程池可以重用内部的线程,从而避免了线程的创建和销毁带来的性能开销,

2 线程池可以有效的控制线程的最大并发数,避免了大量线程因互相抢占系统资源而导致阻塞现象的发生。

3 因此在实际开发中应尽量采用线程池,而不是每次都要创建一个Thread对象。

8 响应时间优化

响应速度包括启动速度——点击APP按钮到APP首页完全打开的过程尽可能快;页面响应速度——用户执行点击、滑动等操作后,页面能快速响应。APP不能产生卡顿、更不能出现ANR。

具体优化措施有:

  • 耗时操作应放入子线程进行处理,不能阻塞主线程。

  • SDK等资源应采用懒加载方式,需要时才进行加载,不需要时可不必加载。

  • 线上环境避免打印大量的日志。

  • 使用(发 可 特 瑞) BitmapFactory.Option 的inBitmap变量,来复用旧的Bitmap,避免为新Bitmap多次分配内存以及销毁旧Bitmap(如果该Bitmap使用频率高的话)

  • 优化view视图渲染时间:

①若view视图比较复杂,可考虑使用ConstraintLayout约束布局,减少视图渲染的层级。

②若view视图比较简单,优化考虑使用LinearLayout水平布局(因为LinearLayout的渲染时间比ConstraintLayout、 RelativeLayout都要短)。

③避免过度渲染,如果有多个view的背景重叠在一起,可以考虑去掉底层被覆盖的view;主题 theme可以设置为NoBackground模式。

④若view视图在需要时才被创建,使用ViewStub控件。

recyclerview列表控件优化:

①item 的view视图优化,同第4点。

②增加recyclerView的item缓存数量,将网络请求的数据缓存,避免二次请求网络。

③在 onBindViewHolder 避免执行耗时操作,因为onBindViewHolder是在主线程执行,onBindViewHolder加耗时操作会影响滑动流畅度。

④如果不需要RecyclerView的默认动画,删除。(如刷新时闪烁的动画效果)

⑤RecyclerView 刷新时尽量使用局部刷新,避免全局刷新。

备注:查看view是否过度渲染可在手机开发者模式开启以下设置:

9 内存优化-(cpu 耗电)

减少内存的使用,主要是避免创建过多对象占用过多内存、避免内存抖动以及避免内存泄漏。

内存抖动:即频繁地创建和销毁内存,在这个过程中,垃圾回收器也会频繁工作,对内存性能造成影响。

内存泄漏:即应该被GC回收的内存,由于还在被其他对象引用,导致无法被回收。内存泄漏是比较严重的问题,过多的内存泄漏会导致内存溢出,产生OOM的系统错误。

(1)造成内存泄漏的原因主要有:

  • 单例类引用Context造成内存泄漏。

  • 非静态内部类引用外部类造成内存泄漏。

  • handler引用activity造成内存泄漏。

  • 属性动画没有取消,导致view一直被引用造成内存泄漏。

  • 监听器没有取消、回调没有反注册。

内存优化的措施有:

  • 使用线程池复用线程,因为线程本身会占用相对比较大的内存,复用就可以省下部分内存。

  • 在onDraw方法内避免创建对象。因为onDraw会被频繁调用,导致其内部的对象也会被频繁创建,占用过多内存。

  • 尽量使用StringBuilder或StringBuffer拼接字符串,减少String的使用。(因为拼接字符串时,String会创建新的对象,而StringBuilder、StringBuffer是在原字符串基础上拼接)

  • 视图资源不可见时进行清除,避免占用内存。如Bitmap执行.Recycle方法进行清除、对图片和(楼 特)lottie资源进行销毁。

针对内存泄漏的问题进行优化:

①单例类应引用Application的Context,因为Application的Context的生命周期是和APP一致的,不会造成单例类引用某个activity的context以致该activity无法被回收的问题。

②将非静态内部类改为静态内部类,这样就不会引用外部类。

③handler:a.handler使用结束时调用remove Callbacks And Messages(null)清除队列;

b.静态内部类+弱引用方式可避免内存泄漏。

④属性动画、监听器使用结束应及时取消,广播或其他一些外部库的回调应该及时反注册。

(2)CPU优化

CPU的作用是计算处理信息、运行程序,因此优化的方向就是减少CPU计算的工作,提升CPU的计算效率。

具体的优化措施有:

  • 避免主线程执行耗时任务,耗时任务在子线程异步执行。

  • 避免在onDraw方法里执行大量耗时操作。

  • 暂时不需要用到的信息进行懒加载、延迟初始化。

(3)耗电量优化

优化的措施有:

  • 避免频繁进行网络请求。

  • 避免任务被频繁执行,可以等任务形成一定数量时,再一起执行。

  • 避免应用频繁唤醒屏幕。(频繁唤醒屏幕会导致系统无法进入休眠,耗电量大)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值