Android 性能优化

一、绘制优化

Android应用启动慢,经常卡顿,按照场景分可分为两大类:

页面绘制:

主要原因是绘制的层级深,页面复杂,刷新不合理。大多数场景是页面初始化或者页面跳转。

数据处理:

主要原因是数据处理量太大,一般分为三种情况:

数据处理在UI线程;数据处理占用CPU高;内存增加导致GC频繁。

Android的显示过程可以简单概括为:应用层把经过测量、布局、绘制后的surface缓存数据,通过SurfaceFlinger把数据显示到屏幕上。应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层。

应用层:

Measure:使用深度优先原则递归得到所有视图的宽高;
Layout:使用深度优先原则递归得到所有视图的位置;

Draw:支持两种绘制:软件绘制(CPU)和硬件加速(GPU)

系统层:

Android显示系统使用了匿名共享内存:

SharedClient,每个应用和SurfaceFlinger之间都会创建一个SharedClient,最多可以创建31个SharedBufferStack集合,每个Surface都对应一个SharedBufferStack,也就是一个Window。

应用层绘制到缓存区,SurfaceFlinger把缓存区数据渲染到屏幕,由于两个进程都使用了Android的匿名共享内存SharedClient。

绘制过程是CPU准备数据,通过Driver层把数据交给CPU渲染,其中CPU主要负责Measure,Layout,Record,Execute的数据计算工作,GPU负责Rasterization渲染。

卡顿的根本原因:

绘制任务太重,绘制一帧内容耗时太长。主线程太忙了,导致VSync信号来时还没有准备好数据,导致丢帧。

主线称要做的工作:

UI生命周期控制,

系统事件处理
消息处理

页面布局

页面绘制

页面刷新

绘制分析工具:GPU呈现模式分析和过度绘制监测

如何避免过度绘制:

布局上优化:include,merge,ViewStub

布局层级越少,加载速度越快。

减少同一层级控件的数量,加载速度就会变快。

一个控件的属性越少,解析越快。

尽量多使用RelativeLayout,LinearLayout和ConstraintLayout。

尽可能少用wrap_content,wrap_content会增加布局measure的计算成本。

onDraw中不要创建新的局部变量,同时onDraw不能做耗时的任务。

移除XML中非必须的背景;

移除Window默认的背景;

按需显示占位背景图片

自定义View优化:

在自定义View中可以通过canvs.clipRect()来帮助系统识别哪些区域可见,才绘制哪些区域。

二、内存优化

对象生命周期

创建阶段

应用阶段

不可见阶段

不可达阶段

收集阶段

终结阶段

对象空间重新分配阶段

创建对象后,在确认不需要使用该对象时,使对象置空。

访问本地变量优于访问类中的变量。

内存泄漏:

webview 造成的泄漏

资源对象未关闭

集合中的对象没清理

Bitmap对象

监听器未关闭

非静态内部类的静态实例

Handler内存泄漏

单例模式导致的内存泄漏

属性动画导致的内存泄漏

监听内存泄漏:

LeakCanary

内存空间优化

对象引用:强引用,软引用,弱引用,虚引用。
减少不必要的内存开销
在java中尽量使用基本数据类型,使用最优的数据类型(HashMap与ArrayMap)

不要大量使用枚举类型。

ANR:

Activity的UI在5秒内没有响应输入事件(按键按下,屏幕触摸)

BroastcastReceiver在10秒内没有执行完毕

Service在特定时间内(20秒内)无法处理完成。

主线程频繁进行IO操作;

硬件操作如进行调用照相机或者录音等操作;

多线程操作的死锁,导致主线程等待超时;

主线程操作调用join()方法、sleep()方法或者wait()方法;

System server中发生WatchDog ANR;

service binder的数量达到上限。

Context
Application:Android应用中的默认单例类,在Activity或者Service中通过getApplication()可以获取到这个单例,通过context.getApplicationContext()可以获取到应用全局唯一的Context实例。

Activity/Service:这两个类都是ContextWrapper的子类,在这两个类中可以通过getBaseContext() 获取他们的Context实例,不同的Activity或者Service实例,他们的Conetxt都是独立的,不会复用。

BroastcastReceiver:和Activity以及Service不同,BroastcastReceiver本身并不是Context的子类,而是在回调函数onReceive中由Android框架传了一个Context实例。

ContentProvider:同样的,ContentProvider也不是Context的实例。通过getContext()获取Context实例。如果ContentProvider和调用者处于相同的应用进程中,getContext()将返回全局唯一的Context实例。

如果不是,那么ContentProvider持有自身所在进程的Context实例。

Context的应用场景
ApplicationActivityServiceContentProvidProviderBroastcaseReceiver
Show a DialogNOYESNONONO
Start an ActivityNO1YESNO1NO1NO1
Layout InflationNO2YESNO2NO2NO2
Start a ServiceYESYESYESYESYES
Bind to a ServiceYESYESYESYESNO
Send a BroadcastYESYESYESYESYES

Register

BroastcastReceiver

YESYESYESYESNO3
Load Resource ValuesYESYESYESYESYES

数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task,添加FLAG_ACTIVITY_NEW_TASK。一般情况不推荐。
数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。

三、包体积优化

res资源优化

只使用一套图片,使用高分辨率的图片。图片使用WebP。

代码优化,Lint工具检查无用文件,将无用的文件列在“UnusedResources:Unused resources”

代码混淆

使用proGuard代码混淆器工具

assets资源优化

音频文件使用有损压缩格式。对ttf字体文件压缩,可以采用FontCreator工具只提取你需要的字体。

lib资源优化

动态下载的资源

一些模块的插件化动态添加

so文件的过滤与适配。

四、其他优化

ListView和Bitmap优化

ListView分三部分:

采用ViewHolder;根据列表的滑动状态来控制任务的执行频率;开启硬件加速

Bitmap优化:主要是通过BitmapFactory.Options来根据需要对图片进行采样。inSampleSize。

线程优化,采用线程池;

避免创建过多的对象;

不要过多使用枚举,枚举占用的内存空间要比整型大;

常量请使用static final来修饰;

使用Android特有的数据结构,SparseArray和Pair;

适当使用软引用和弱引用;

采用内存缓存和磁盘缓存;

尽量采用静态内部类。

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值