前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android-App性能优化

Android-App性能优化

作者头像
android_薛之涛
发布2018-09-12 10:47:38
2.2K0
发布2018-09-12 10:47:38
举报
文章被收录于专栏:Android-薛之涛

上一篇我们讲了java的引用机制,今天我们来一下和它有关的app性能优化(其实也不是很大)。

性能优化的目标

代码语言:javascript
复制
     在网上也看到过很多相关的文章,他们基本总结为:快,稳,省,小,描述的很准确.如下图

(注:此图不知道啥时候收集的,如有侵权,立删):

代码语言:javascript
复制
 如何让app在运行过程过不卡顿,运行流畅,速度快,也就是说如何解决卡顿呢?我们先看看那些因素影响卡顿?
1. UI,包括ui的绘制,刷新等
2. 启动,包括冷启动,热启动,温启动等
3. 跳转,页面跳转,前后天切换
4. 及时反馈,点击事件,滑动,系统事件
UI

这个涉及到android的系统显示原理,我们简单了解一下:

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

换一种方式说:Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需的 60FPS。(注:FPS 表示每秒传递的帧数。)在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 左右。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就无法正常进行正常渲染,这样就发生了丢帧现象。也就是延迟了,这种现象在执行动画或滑动列表比较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,无法在 16ms 完成渲染,最终引起刷新不及时.

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

布局优化
  • 避免ui布局优化可以先从合理使用背景色开始,比如:如果子view和父布局公用一个背景色就没有必要了。
  • 减少不必要的嵌套,一般建议不超过5层
  • 合理使用各种布局,尽量使用LinearLayout和FrameLayout,因为RelativeLayout需要比较复杂,测绘也比较费时,强调一下这个是相对的,不是说LinearLayout一定比RelativeLayout好。
  • 合理使用include、merge和ViewStub,使用include和merge增加复用,减少层级;ViewStub按需加载。
  • 推荐使用google已经出来的新的布局ConstraintLayout,这个有机会说。
绘制优化

-我们之前说过根据Android系统显示的原理,View的绘制频率保证60fps是最佳的,这就要求每帧绘制时间不超过16ms(16ms = 1000/60),因此要减轻onDraw()的负担。所以在绘制时要注意两点:

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

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

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

启动优化
冷启动

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

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

1、加载并启动应用程序

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

3、创建应用程序进程

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

  • 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操作、反序列化、网络操作、布局嵌套等。

主线程优化

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

  • 集合类泄漏
  • 单例/静态变量造成的内存泄漏
  • 匿名内部类/非静态内部类
  • 资源未关闭造成的内存泄漏

解决方式:

  1. 比如我们的List集合add()元素之后,会引用着集合元素对象,导致该集合中的元素对象无法被回收,从而导致内存泄露。当我们的List集合没有用的时候,一定要
代码语言:javascript
复制
     list.clear()
     list=null
  1. 针对单例引起的内存泄漏,通常是由于引用的context是生命周期短造成的,也就是说生命周期长的持有了生命周期短的引用,造成了内存泄漏。比如Toast,我们传入的是MainActivity,但MainActivity没有用了,需要被销毁,但我们的Tost依然持有其引用导致无法回收,这就导致了内存泄漏。
  2. 匿名内部类或非静态内部类导致的内存泄漏,这个我们可以采用合理使用JAVA的引用机制来解决,我上一篇文章有详解,参考Android-强,软,弱,虚引用.

4.资源未关闭导致的内存泄漏就比较好说了,我们平时要多检查,用完后及时关闭无用资源。

4.1 网络、文件等流忘记关闭

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

4.3 Service 执行完后忘记 stopSelf()

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

4.5 注意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体积的方式。

  • 省电:谷歌推荐使用JobScheduler,来调整任务优先级等策略来达到降低损耗的目的。JobScheduler可以避免频繁的唤醒硬件模块,造成不必要的电量消耗。避免在不合适的时间(例如低电量情况下、弱网络或者移动网络情况下的)执行过多的任务消耗电量。这个我们以后说。
  • 省内存:主要是加载图片,动不动就 OOM,对于图片的压缩无非是:
  • 图片尺寸压缩
  • 图片质量压缩 此处代码省略,网上一大堆。 Glide就是采用了Lrucache和LruDiskCache推荐使用。
  • 省cpu资源. 比如:线程的使用,这里我推荐使用线程池,我也写过相关文章,感兴趣的可以了解一下。Android-ThreadPooll.

其他

这都是本人的一些建议:

  • 序列化采用推荐的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等

PgOnSI.png

基本也说这么多,以后再补充。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 性能优化的目标
            • 其他
            相关产品与服务
            云服务器
            云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档