Android 性能优化【转】

性能优化的目标

基本总结为:快,稳,省,小

如下图

一、快

如何让 app 在运行过程过不卡顿,运行流畅,速度快,也就是说如何解决卡顿呢?

我们先看看那些因素影响卡顿? 

UI-----包括ui的绘制,刷新等 

启动I-----包括冷启动,热启动,温启动等 

跳转I-----页面跳转,前后台切换 

及时反馈I-----点击事件,滑动,系统事件

1.UI

 android 的系统显示原理

Android 显示过程可以简单概括为:Android 应用程序把经过测量,布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上, 通过 Android 的刷新机制来刷新数据。

也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。

换一种方式说:Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需的 60FPS。(注:FPS 表示每秒传递的帧数。)

在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 左右。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就无法正常进行正常渲染,这样就发生了丢帧现象。也就是延迟了,这种现象在执行动画或滑动列表比较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,无法在 16ms 完成渲染,最终引起刷新不及时.

那么我们如何解决呢,主要从两点入手:ui布局,绘制优化和主线程优化?

(1)布局优化

避免ui布局优化可以先从合理使用背景色开始,比如:如果子view和父布局公用一个背景色就没有必要了。

减少不必要的嵌套,一般建议不超过5层

合理使用各种布局,尽量使用 LinearLayout 和 FrameLayout,因为 RelativeLayout 需要比较复杂,测绘也比较费时,强调一下这个是相对的,不是说 LinearLayout 一定比 RelativeLayout 好。

合理使用 include、merge 和 ViewStub,使用include和merge增加复用,减少层级; ViewStub 按需加载。

推荐使用 google 已经出来的新的布局 ConstraintLayout,这个有机会说。

(2)绘制优化

我们之前说过根据 Android 系统显示的原理,View 的绘制频率保证 60fps 是最佳的,

这就要求每帧绘制时间不超过16ms(16ms = 1000/60),因此要减轻 onDraw() 的负担。

所以在绘制时要注意两点:

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

onDraw 方法中不要做耗时的任务。

还有就是刷新,刷新的话尽量减少不必要的刷新和尽可能减少刷新面积

2.启动优化

冷启动:冷启动是指安装 apk 后首次启动应用程序,或者应用程序上次结束,进程被杀死后重新打开app.

在冷启动开始时,系统有三个任务。这些任务是:

加载并启动应用程序

启动后立即显示应用程序的空白启动窗口

创建应用程序进程

当系统为我们创建了应用进程之后,会执行以下的操作:

application 的初始化

启动 UI 线程

创建 Activity

导入视图(inflate view)

计算视图大小(onmesure view)

得到视图排版(onlayout view)

绘制视图(ondraw view)

应用程序进程完成首次绘制后,系统进程会交换当前显示的背景窗口,将其替换为主活动。

此时至此启动完成,用户可以使用程序(app)了,那么这里就会有两类创建:

Application 的创建

当 Application 启动时,会有一个空白的启动窗口保留在屏幕上,直到系统首次完成绘制应用程序,白屏才会消失,这也是为什么启动app会出现白屏,这个问题,我也有提到过解决方式 Anroid 白屏

Activity的创建

当 Application 首次启动完成绘制后,我们的 UI 线程会执行主活动进行以下操作:

初始化值。

执行其构造函数。

执行其回调方法,比如 Activity 的 onCreate()对应生命周期的状态,onCreate() 方法做的事情越多,冷启动消耗的时间越长。

暖(温)启动

暖启动比冷启动时间更短。在暖启动中,系统都会把你的 Activity 带到前台。如果应用程序的 Activity 仍然驻留在内存中,那么应用程序可以避免重复对象初始化、布局加载和渲染,但系统依然会展示闪屏页,直到第一个 Activity 的内容呈现为止。比如:当应用中的 Activities 被销毁,但在内存中常驻时,应用的启动方式就会变为暖启动 。

热启动

热启动的启动时间比暖启动还要更短。你比如,我用户 Back 退出应用程序,然后又重新启动,应用程序会再次执行 Activity 的 onCreate(),但会从 Bundle(savedInstanceState)获取数据,我们平时应用成勋崩溃,也是通过该方法保存数据。

针对启动方式的优化

Application 的创建过程中尽量少的进行耗时操作。

比如:

Application 的 onCreate() 中进行友盟,bugly, okhttp,地图,推送等 init() 等操作。

如果是必须在 onCreate 中进行的如:okhttp 等网络请求框架我们在 onCreate 中进行,其他的友盟,百度地图啥的我们可以等程序起来后再 onResume 方法中执行,bugly 等 sdk 可以异步加载。

在生命周期回调的方法中尽量减少耗时的操作

这个里面的优化方式就是:避免 I/O 操作、反序列化、网络操作、布局嵌套等。

二、稳

主线程优化

主线程的优化大部分是指内存优化,不是指内存泄漏,那么通常那些地方容易引起内存泄漏呢?

集合类泄漏

单例/静态变量造成的内存泄漏

匿名内部类/非静态内部类

资源未关闭造成的内存泄漏

解决方式

集合

比如我们的List集合add()元素之后,会引用着集合元素对象,导致该集合中的元素对象无法被回收,从而导致内存泄露。

当我们的List集合没有用的时候,一定要

list.clear()

list=null

单例

针对单例引起的内存泄漏,通常是由于引用的context是生命周期短造成的,也就是说生命周期长的持有了生命周期短的引用,造成了内存泄漏。比如Toast,我们传入的是MainActivity,但MainActivity没有用了,需要被销毁,但我们的Tost依然持有其引用导致无法回收,这就导致了内存泄漏。

匿名内部类或非静态内部类

匿名内部类或非静态内部类导致的内存泄漏,这个我们可以采用合理使用JAVA的引用机制来解决,

参考Android-强,软,弱,虚引用.

资源未关闭

资源未关闭导致的内存泄漏就,平时要多检查,用完后及时关闭无用资源:

网络、文件等流忘记关闭

手动注册广播时,退出时忘记 unregisterReceiver()

Service 执行完后忘记 stopSelf()

EventBus 等观察者模式的框架忘记手动解除注册

注意 Bitmap,用完及时 Recycle()

三、小

小多指应用程序apk体积要小。

我们先看看一个apk文件有哪些解压后有哪些文件:

assets 文件夹

存放一些配置文件、资源文件,assets 不会自动生成对应的 ID,而是通过 AssetManager 类的接口获取。

res 目录

res 是 resource 的缩写,这个目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中,访问直接使用资源 ID。

META-INF

保存应用的签名信息,签名信息可以验证 APK 文件的完整性。

AndroidManifest.xml

这个文件用来描述 Android 应用的配置信息,一些组件的注册信息、可使用权限等。

classes.dex

Dalvik 字节码程序,让 Dalvik 虚拟机可执行,一般情况下,Android 应用在打包时通过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。

resources.arsc

记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。

通常我减小 apk 体积的方式都是:先用 studio 自带的代码扫描分析工具 lint 删除无用资源;

开启混淆,设置   shrinkResources true和 minifyEnabled true;

当然你也可以借助第三方工具如 :乐固加固,360压缩啥的;

还有注意不要重复使用库;

插件化,比如功能模块放在服务器上,按需下载,可以减少安装包大小等都是常见的减少 apk 体积的方式。

四、省

1.省电

谷歌推荐使用 JobScheduler,来调整任务优先级等策略来达到降低损耗的目的。

JobScheduler 可以避免频繁的唤醒硬件模块,造成不必要的电量消耗。

避免在不合适的时间(例如低电量情况下、弱网络或者移动网络情况下的)执行过多的任务消耗电量。这个我们以后说。

2.省内存

主要是加载图片,动不动就 OOM,对于图片的压缩无非是:

图片尺寸压缩

图片质量压缩

此处代码省略,网上一大堆。

Glide就是采用了 Lrucache 和 LruDiskCache 推荐使用。

3.省 cpu 资源

比如:线程的使用,这里我推荐使用线程池,相关文章,感兴趣的可以了解一下。

Android-ThreadPooll.://www.greatytc.com/p/07eb2f7db0ee

4.其他

一些建议:

序列化采用推荐的 Parcelable 代替 Serializable

集合如果是插入和删除用的多,建议使用 LinkList。如果修改用的多,建议 ArrayList。

写程序要思考,避免创建不必要的对象。

对常量使用 static final,适用于基本类型和 String 常量。

使用增强的 for 循环语法(foreach)。

避免使用浮点数,浮点数比 Android 设备上的整数慢约2倍。

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

删除控件中无用的属性。

合理使用动画,某些情况下可以用硬件加速方式来提供流畅度,或者采用自定义view代替动画,最后记得在Activity的ondestory()方法中调用Animation.cancle()进行动画停止。

注意 webview 和 handler,一般在首次加载后 webview 就会存在于内存中,容易内存泄漏。

考虑 StringBuilder 代替 String

数据量比较大或者内存比较宽裕考虑 HashMap,其他建议使用 SpareArray

五、工具

最后,我们一定要学会使用 Android Studio 自带的各种工具如:

Lint:提示未使用到资源,不规范的代码,优化建议等。

使用:选择 Analyze > Inspect Code 具体百度

使用 Android Profiler 查看内存,已经各个操作内存和网络的变化。

借助第三方工具,这个就多了去了,比如 LeakCanary,MemoryAnalyzer 等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容