Android App优化:内存优化、电量优化、网络优化等 (2)

-- 优化专题:

  整理一系列的专题:比如APK瘦身、插件化、程序架构、性能优化、自定义view、增量升级、移动开发各种技术解决方案等。
  Android后期发展的五大趋势:一、性能优化;二、高级UI;三、JNI/NDK开发;四、架构师;五、RN开发;
  性能优化有那几个方面:一、内存优化;二、UI优化(布局优化和绘制优化);三、速度的优化(线程优化/网络优化);四、电量优化;五、启动优化;
  Android的渲染机制,内存与GC,电量优化。电量优化,网络优化,Wear上如何做优化,使用对象池来提高效率,LRU Cache,Bitmap的缩放,缓存,重用,PNG
压缩,自定义View的性能,提升设置alpha之后View的渲染性能,以及Lint,StictMode等等工具的使用技巧。

Android性能测试(内存、cpu、fps、流量、GPU、电量)——adb篇- https://www.iqiyi.com/v_19rsmqlrrk.html?vfm=2008_aldbd

- Android移动性能实战- https://blog.csdn.net/pzmyangkong/article/details/79882440
 磁盘优化;内存优化;网络优化;流畅度;CPU优化;电池优化;响应时延

  常见的优化一般分为性能优化,资源优化,稳定性优化三方面,优化方案也可以分为有损和无损两种。
  APP性能指标:安全、启动时间;CPU占用;内存占用;流量;电量。
1.内存优化
2.电量优化

3.网络优化

https://i-blog.csdnimg.cn/blog_migrate/6f35e34dd3167aebc46b2af2877be624.jpeg

> 内存优化,性能优化、代码优化
Android性能优化典范 - 第1季 http://hukai.me/android-performance-patterns/
Android性能优化典范 - 第2季 http://hukai.me/android-performance-patterns-season-2/
Android 性能优化典范(六)-- http://geek.csdn.net/news/detail/106513
Android性能优化之渲染篇- http://hukai.me/android-performance-render/
Android性能优化之运算篇- http://hukai.me/android-performance-compute/
Android性能优化之内存篇- http://hukai.me/android-performance-memory/

Android内存优化大全(上):http://blog.csdn.net/hewence1/article/details/39004231
Android内存优化大全(中):http://blog.csdn.net/hewence1/article/details/39004301
Android最佳性能实践(2):分析内存的使用情况: http://android.jobbole.com/81242/
Android最佳性能实践(3):高性能编码优化 http://android.jobbole.com/81245/
Android最佳性能实践(4):布局优化技巧 http://android.jobbole.com/81248/

Android最佳性能实践(一)——合理管理内存- http://blog.csdn.net/guolin_blog/article/details/42238627
Android官方,APP的内存管理-- http://blog.csdn.net/sahadev_/article/details/52317525
Android 性能优化的一些建议: http://blog.csdn.net/a56573016613/article/details/48291191
APP 更流畅的 5 个改进建议: http://android.jobbole.com/83111/
Android界面性能调优手册: http://android.jobbole.com/82548/
Android性能优化典范: http://android.jobbole.com/80611/

通过Hardware Layer提升Android动画性能 http://android.jobbole.com/82294/
正确使用Android性能分析工具TraceView- http://android.jobbole.com/78995/
Android的进程与线程 -http://android.jobbole.com/80640/
如何通过技术优化让 Android 程序变得流畅?-- http://www.zhihu.com/question/30138734
[魅族Degao]Android客户端性能优化-- http://blog.csdn.net/yueqian_scut/article/details/50762649#comments
Android性能优化之提高ListView性能的技巧-- http://blog.csdn.net/nugongahou110/article/details/47128125
Android性能优化总结--http://blog.csdn.net/woyaowenzi/article/details/9273839
Android性能优化全方面解析- http://blog.csdn.net/sw950729/article/details/72124008
Android应用开发性能优化完全分析-http://blog.csdn.net/u014651216/article/details/50787674
APP性能优化系列- http://blog.csdn.net/a910626/article/category/3147827
Android性能优化- http://blog.csdn.net/u010687392/article/category/3197917
Android高级之十二讲之如何降低应用内存消耗-http://blog.csdn.net/reboot123/article/details/53542349
手机淘宝性能优化- https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=203394618&idx=1&sn=58b05aaf205b20c361935a02282392d9&scene=23&srcid=0604MsP7tTbo6cELNNdVYQ9O#rd

关于烂代码的那些事 - 为什么每个团队存在大量烂代码 http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=403520625&idx=1&sn=c59f3944760a055ee7b6d1dda4431e0a&scene=23&srcid=01138qxBuGkMMdTiBO6FyrjG#rd

微信为啥这么省流量(技术宅入)http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=400163013&idx=1&sn=911cf71925e2ba50d47955a713134acb&scene=21#wechat_redirect

Java中关于内存泄漏出现的原因以及如何避免内存泄漏(超详细版汇总上)-- https://mp.weixin.qq.com/s?__biz=MzA5MzY4NTQwMA==&mid=2650995848&idx=2&sn=8985414234aca4f97360cb1c6e71d15b&scene=0&key=7b81aac53bd2393d8aee53fe6a7be1c2154c82b7f5dd6bae906f1a454056621536a166c144867eb9de56cac20e570233&ascene=7&uin=MjAyNjIyNTc0MQ%3D%3D&devicetype=android-23&version=26031933&nettype=WIFI&pass_ticket=TUwnC9FHWHu6OL%2F2wKyY%2F8R8agD9Z1ZenGu8v1lc3W24YuXQxvQ2b0JIOl%2FJyC2m

-- 优化的金科玉律不外乎以下内容:
  1.良好的设计将会使优化变得更加容易。
  2.过早的优化并不能解决多有的性能问题,但是不良的设计将会导致优化难度的增加。

-- OOM: 1,压缩图片,主动释放Bitmap的内存(大对象);2,设计Cache。Runtime.getMaxMemory()

Android性能优化——如何避免OOM总结- http://blog.csdn.net/sinat_15877283/article/details/50776228
  首先是减小对象的内存占用,其次是内存对象的重复利用,然后是避免对象的内存泄露,最后是内存使用策略优化。
  原因:1、加载对象过大 ; 2、相应资源过多,没有来不及释放。

-- 解决OOM这样的问题:
 一:在内存引用上做些处理,常用的有软引用、强化引用、弱引用
 二:在内存中加载图片时直接在内存中做处理,如:边界压缩.
 三:动态回收内存
 四:优化Dalvik虚拟机的堆内存分配
 五:自定义堆内存大小

- android中OOM常见的原因:
 1.数据库的cursor没有关闭。
 2.构造adapter没有使用缓存contentview。
 3.调用registerReceiver()后未调用unregisterReceiver().
 4.未关闭InputStream/OutputStream。
 5.Bitmap使用后未调用recycle()。
 6.Context泄漏。
 7.static关键字等。

-- 手机卡顿出现的原因:
 1,布局过于复杂:xml布局文件可能存在深层嵌套或者组件过多;
 2,重复绘制:一个界面的某一点可能在同一时间进行了多次绘制;
 3,内存抖动:系统内存是有限的,系统经常会将不活跃的进程置入外存中就是常说的虚拟内存,当调用它时再把它从外存转入内存,内存外存转换频率过大就会导致内存抖动;
 4,性能瓶颈: 任务过多且执行调度不够好;
 5,历史问原因,老代码以及设计问题;
 6,团队人众多员 ,存在过多的代码合并和插入问题;
 7,个别程序员的渣代码

-- 携程移动端性能优化-- http://geek.csdn.net/news/detail/132313
  原先的心跳机制是 TCP 长连接池中的空闲 TCP 连接每 60 秒发送一个心跳包到 Gateway,Gateway 返回一个心跳响应包,从而让双方确认 TCP 连接有效。
  衡量一个 App 性能和质量,首先需要了解 App 性能的现状,即 App 端性能的采集。常规的技术方案有两种:
1.使用第三方性能采集 SDK,例如 OneAPM、听云等;
2.自主研发:携程为了完整掌握用户数据采用了自己研发的方式:App 通过日志 SDK 采集日志包括行为埋点和性能埋点,上传至日志服务端,日志消息经 Kafka 消息队列存入 HDFS(RCFile 格式)分布式文件存储系统,后期的数据查询均基于 Hive 系统来实现。
  App 端的性能数据会在多种纬度(操作系统、App 版本、网络状况、位置)下采集网络(网络服务成功率、平均耗时、耗时分布等)、定位(经纬度成功率、城市定位成功率等)、启动时间、内存流量等各类指标。其中像网络服务性能是对于用户体验至关重要的端到端性能,也是优化的核心依据。
  让整个打包流程自动化,同时这个平台还提供了 HotFix 发布平台、App 应用性能管理、App Crash 数据采集等工具,同时可以实现 Daily/Hourly Build,无缝集成自动化测试,集成了 Sonar 代码扫描去检测重复代码等和 infer null pointer,然后能生成一个代码健康度扫描报告,并能帮助分析和解决问题。

  App 性能优化成为各大公司重点关注的问题,目的就是为了提升用户的使用体验。性能优化是一个持续发展的实践课题,可以持续贯穿于我们日常的开发工作中,即随着手机机型的日益碎片化,程序功能的复杂化多样化,总之移动端技术的性能优化是没有尽头的,我们会继续持续关注移动端的性能优化,并融入新的技术进行迭代更新。

-- Android内存优化:ArrayMap- http://blog.csdn.net/bdmh/article/details/49176001
  - ArrayMap用的是copy数据,所以效率相对要高。
1.ArrayMap提供了数组收缩的功能,在clear或remove后,会重新收缩数组,是否空间
2.ArrayMap采用二分法查找(见 android.support.v4.util.ContainerHelpers中的binarySearch方法)
  - Handler避免内存泄露:
1、用static声明handler,静态类不会引用外部类
2、如果Handler中必须用到Activity,那就用WeakReference去引用
3、在Activity结束或暂停的事件中,removeMessages或者removeCallbacksAndMessages将消息队列中的消息移除(避免满足上面两条后,当Activity关闭了,但是Handler还未处理到,造成内存泄露)

-- 一定程度上减少Java内存的无谓消耗:
 1.减少new对象。每次new对象之后,都要开辟新的内存空间。这些对象不被引用之后,还要回收掉。因此,如果最大限度地合理重用对象,或者使用基本数据类型替代对象,都有助于节省内存;
 2.多使用局部变量,减少使用静态变量。局部变量被创建在栈中,存取速度快。静态变量则是在堆内存;
 3.避免使用finalize,该方法会给GC增添很大的负担;
 4.如果是单线程,尽量使用非多线程安全的,因为线程安全来自于同步机制,同步机制会降低性能。例如,单线程程序,能使用HashMap,就不要用HashTable。同理,尽量减少使用synchronized
 5.用移位符号替代乘除号。eg:a*8应该写作a<<3
 6.对于经常反复使用的对象使用缓存;
 7.尽量使用基本类型而不是包装类型,尽量使用一维数组而不是二维数组;
 8.尽量使用final修饰符,final表示不可修改,访问效率高
 9.单线程情况下(或者是针对于局部变量),字符串尽量使用StringBuilder,比StringBuffer要快;
 10.String为什么慢?因为String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。如果不能保证线程安全,尽量使用StringBuffer来连接字符串。这里需要注意的是,StringBuffer的默认缓存容量是16个字符,如果超过16,apend方法调用私有的expandCapacity()方法,来保证足够的缓存容量。因此,如果可以预设StringBuffer的容量,避免append再去扩展容量。如果可以保证线程安全,就是用StringBuilder。

-- 代码优化一些小地技巧:
 1.对常量使用static修饰符。
 2.使用静态方法,静态方法会比普通方法提高15%左右地访问速度。
 3.减少不必要的成员变量,这点在Android Lint工具上已经集成检测了,如果一个变量可以定义为局部变量,则会建议你不要定义为成员变量。
 4.减少不必要的对象,使用基础类型会比使用对象更加节省资源,同时更应该避免频繁穿件短作用域的变量。
 5.尽量不要使用枚举、少用迭代器。
 6.对Cursor、Receiver、Sensor、File等对象,要非常注意对他们的创建、回收与注册、解注册。
 7.避免使用IOC框架,IOC通常使用注解反射来进行实现,虽然现在Java反射的效率已经进行了很好的优化,但大量使用反射依然会带来性能的下降。
 8.使用RenderScript、OpenGL来进行非常复杂的绘图操作。
 9.使用SurfaceView来替代View进行大量、频繁的绘图操作。
 10.尽量使用视图缓存,而不是每次都之下inflate()方法解析视图。--

--  Android性能优化技巧
 1.http用gzip压缩,设置连接超时时间和响应超时时间
  http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读。
 2.listview 性能优化
  1).复用convertView,在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外。
  2).异步加载图片,item中如果包含有webimage,那么最好异步加载
  3).快速滑动时不显示图片. ViewHolder
  当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来
 3.使用线程池,分为核心线程池和普通线程池,下载图片等耗时任务放置在普通线程池,避免耗时任务阻塞线程池后,导致所有异步任务都必须等待
 4.异步任务,分为核心任务和普通任务,只有核心任务中出现的系统级错误才会报错,异步任务的ui操作需要判断原activity是否处于激活状态
 5.尽量避免static成员变量引用资源耗费过多的实例,比如Context
 6.使用WeakReference代替强引用,弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。
 7.超级大胖子Bitmap
  a.及时的销毁(Activity的onDestroy时,将bitmap回收);
  b.设置一定的采样率;
  c.巧妙的运用软引用;
  d.drawable对应resid的资源,bitmap对应其他资源;
 8.保证Cursor 占用的内存被及时的释放掉,而不是等待GC来处理。并且 Android明显是倾向于编程者手动的将Cursor close掉
 9.线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控
 10.如果ImageView的图片是来自网络,进行异步加载
 11.应用开发中自定义View的时候,交互部分,千万不要写成线程不断刷新界面显示,而是根据TouchListener事件主动触发界面的更新

-- App卡顿优化解决方案:
1,减低布局的复杂度;
2,单线程任务不要太多;
3,适当调度;
4,将一些计算分担给服务器端。

-- App性能优化的七大策略:
1.建立监控体系,善用分析工具
2.完善网络基础建设,不断调优
3.利用本地缓存,建立离线化
4.任务分级,合理并行,主线程移除多余操作
5.业务模块懒加载
6.优化页面结构和层次
7.做好图片下载缓存工作

-- App程序卡顿的主要因素就是当时太忙,CPU处理不过来了,或者IO瓶颈。所以如果频繁卡顿,主要原因就是程序结构有不合理的地方。有这样的几个建议,希望各位同仁可以参考: 
 1 统一管理程序中涉及到大量资源的重处理部分。比如,多线程,网络请求,web view,多媒体,持久化等处理 
 2 监控loop的运行时间,找到程序的运行瓶颈。监控读写,发现频繁的IO操作,监控流量,控制请求和返回的处理。
 3 重新审视代码,用好队列。 
 4 如果可能,酌情修改部分服务器端接口,避免一次性处理过多的内容。同时减少json的复杂度也会有帮助。
  先搞清楚 young GC 和 full GC 的区别及耗时差异,我就问一个问题,大部分图片会被 young GC 还是 full GC 回收?
另外大多数图片缓存对 GC 的影响几乎没有区别,只要不和明显有内存泄露的写法对比。对于目前的系统来说,young GC 的耗时对性能影响很小。

-- App性能优化
 1.应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
 2.Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
 3.使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
 4.虽然静态类与非静态类之间的区别并不大,但是对于Android开发者而言却是必须理解的。至少我们要清楚,如果一个内部类实例的生命周期比Activity更长,那么我们千万不要使用非静态的内部类。最好的做法是,使用静态内部类,然后在该类里使用弱引用来指向所在的Activity。
 5.生产者-消费者 模型:生产者线程、消费者线程、任务队列;MessageQueue , Looper , Handler;
 6.每个 View 都持有当前 Context、Activity 的引用,如果子线程持有某个 View 的引用,继而持有了对应 Activity 引用,那么在线程返回之前,即使该 Activity 不可用,也无法回收,这就造成了内存泄漏。
 7.除了持有 View,线程隐式持有 Activity 也可能导致内存泄漏,只要子线程没有结束,引用关系就一直存在。
 8.内部线程工具类持有外部类引用,可能会导致内存泄漏。

-- 代码性能调优点:
性能优化——诊断及工具(TraceView)、性能优化—内存篇、性能优化—JNI篇,性能优化—电量篇。
  主要包括单例模式、同步改异步、缓存、Layout优化、数据库优化、算法优化、延迟执行。
  图片缓存、线程池、View缓存、IO缓存、消息缓存、通知栏notification缓存等,数据库优化

- 性能优化之Java(Android)代码优化- http://www.trinea.cn/android/java-android-performance/
 1、降低执行时间;
 这部分包括:缓存、数据存储优化、算法优化、JNI、逻辑优化、需求优化几种优化方式。
 缓存主要包括对象缓存、IO缓存、网络缓存、DB缓存,对象缓存能减少内存的分配,IO缓存减少磁盘的读写次数,网络缓存减少网络传输,DB缓存较少Database的访问次数。
 2、异步,利用多线程提高TPS;
 3、提前或延迟操作,错开时间段提高TPS;
 4. 网络优化中一些客户端和服务器端需要尽量遵守的准则:;
   a. 图片必须缓存,最好根据机型做图片做图片适配
   b. 所有http请求必须添加httptimeout
   c. 开启gzip压缩
   d. api接口数据以json格式返回,而不是xml或html
   e. 根据http头信息中的Cache-Control及expires域确定是否缓存请求结果。
   f. 确定网络请求的connection是否keep-alive
   g. 减少网络请求次数,服务器端适当做请求合并。
   h. 减少重定向次数
   i. api接口服务器端响应时间不超过100ms
   google正在做将移动端网页速度降至1秒的项目- https://developers.google.com/speed/docs/insights/mobile
 
-- 使用对象池技术有很多好处,它可以避免内存抖动,提升性能,但是在使用的时候有一些内容是需要特别注意的。通常情况下,初始化的对象池里面都是空白的,当使用某个对象的时候先去对象池查询是否存在,如果不存在则创建这个对象然后加入对象池,但是我们也可以在程序刚启动的时候就事先为对象池填充一些即将要使用到的数据,这样可以在需要使用到这些对象的时候提供更快的首次加载速度,这种行为就叫做预分配。使用对象池也有不好的一面,程序员需要手动管理这些对象的分配与释放,所以我们需要慎重地使用这项技术,避免发生对象的内存泄漏。为了确保所有的对象能够正确被释放,我们需要保证加入对象池的对象和其他外部对象没有互相引用的关系。
  Android的Heap空间是不会自动做兼容压缩的,意思就是如果Heap空间中的图片被收回之后,这块区域并不会和其他已经回收过的区域做重新排序合并处理,那么当一个更大的图片需要放到heap之前,很可能找不到那么大的连续空闲区域,那么就会触发GC,使得heap腾出一块足以放下这张图片的空闲区域,如果无法腾出,就会发生OOM。

  相比起JPEG,PNG能够提供更加清晰无损的图片,但是PNG格式的图片会更大,占用更多的磁盘空间。到底是使用PNG还是JPEG,需要设计师仔细衡量,对于那些使用JPEG就可以达到视觉效果的,可以考虑采用JPEG即可。我们可以通过Google搜索到很多关于PNG压缩的工具。

  使用对象池的技术来解决对象频繁创建再回收的效率问题,使用这种方法,bitmap占用的内存空间会差不多是恒定的数值,每次新创建出来的bitmap都会需要占用一块单独的内存区域.

-- 使用inBitmap需要注意几个限制条件:
  在SDK 11 -> 18之间,重用的bitmap大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用。从SDK 19开始,新申请的bitmap大小必须小于或者等于已经赋值过的bitmap大小。
  新申请的bitmap与旧的bitmap必须有相同的解码格式,例如大家都是8888的,如果前面的bitmap是8888,那么就不能支持4444与565格式的bitmap了。
我们可以创建一个包含多种典型可重用bitmap的对象池,这样后续的bitmap创建都能够找到合适的“模板”去进行重用。

-- 通常采用下面三个步骤来解决性能问题。
 1. Gather:收集数据
  我们可以通过Android SDK里面提供的诸多工具来收集CPU,GPU,内存,电量等等性能数据,
 2. Insight:分析数据
  通过上面的步骤,我们获取到了大量的数据,下一步就是分析这些数据。工具帮我们生成了很多可读性强的表格,我们需要事先了解如何查看表格的数据,每一项代表的含义,这样才能够快速定位问题。如果分析数据之后还是没有找到问题,那么就只能不停的重新收集数据,再进行分析,如此循环。
 3. Action:解决问题
  定位到问题之后,我们需要采取行动来解决问题。解决问题之前一定要先有个计划,评估这个解决方案是否可行,是否能够及时的解决问题。

-- Android性能优化典范
  通过StrictMode API在代码层面做细化的跟踪,可以设置StrictMode监听那些潜在问题,出现问题时如何提醒开发者,可以对屏幕闪红色,也可以输出错误日志。
public void onCreate() {
     if (DEVELOPER_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyLog()
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects()
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
     }
     super.onCreate();
}

--  Android性能优化之内存篇
  与C/C++需要通过手动编码来申请以及释放内存有所不同,Java拥有GC的机制。Android系统里面有一个Generational Heap Memory的模型,系统会根据内存中不同的内存数据类型分别执行不同的GC操作。例如,最近刚分配的对象会放在Young Generation区域,这个区域的对象通常都是会快速被创建并且很快被销毁回收的,同时这个区域的GC操作速度也是比Old Generation区域的GC操作速度更快的。
  private void init() {
     ListenerCollector collector = new ListenerCollector();
     collector.setListener(this, mListener);
  }
  上面的例子容易存在内存泄漏,如果activity因为设备翻转而重新创建,自定义的View会自动重新把新创建出来的mListener给绑定到ListenerCollector中,但是当activity被销毁的时候,mListener却无法被回收了。
  Memory Churn内存抖动,内存抖动是因为在短时间内大量的对象被创建又马上被释放。瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,会触发GC从而导致刚产生的对象又很快被回收。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。
-- 三种测量内存的工具,下面再简要概括一下他们各自的特点:
  1. Memory Monitor:跟踪整个app的内存变化情况。
  2. Heap Viewer:查看当前内存快照,便于对比分析哪些对象有可能发生了泄漏。
  3. Allocation Tracker:追踪内存对象的来源。

-- Android性能优化之运算篇
  Android中的Java代码会需要经过编译优化再执行的过程。代码的不同写法会影响到Java编译器的优化效率。例如for循环的不同写法就会对编译器优化这段代码产生不同的效率,当程序中包含大量这种可优化的代码的时候,运算性能就会出现问题。想要知道如何优化代码的运算性能就需要知道代码在硬件层的执行差异。
  使用Android SDK提供的工具,进行仔细的测量,然后再进行微调修复。
-- 为了提升运算性能,这里介绍2个非常重要的技术,Batching与Caching
  Android的Main Thread也是UI Thread,它需要承担用户的触摸事件的反馈,界面视图的渲染等操作。这就意味着,我们不能在Main Thread里面做任何非轻量级的操作,类似I/O操作会花费大量时间,这很有可能会导致界面渲染发生丢帧的现象,甚至有可能导致ANR。防止这些问题的解决办法就是把那些可能有性能问题的代码移到非UI线程进行操作。
  另外一个我们需要注意的运算性能问题是基础算法的合理选择,例如冒泡排序与快速排序的性能差异.避免我们重复造轮子,Java提供了很多现成的容器,例如Vector,ArrayList,LinkedList,HashMap等等,在Android里面还有新增加的SparseArray等,我们需要了解这些基础容器的性能差异以及适用场景。这样才能够选择合适的容器,达到最佳的性能。

-- Apache 的 HttpClient 与 URLConnection 库可以根据当前的 getThreadStatusTag() 值自动给 sockets 加上标记。那些库在通过 keep-alive pools 循环的时候也会为 sockets 加上或者取消标签。给 Socket 加上标签(Socket tagging)是在 Android 4.0 上才被支持的, 但是实际情况是仅仅会在运行Android 4.0.3 或者更高版本的设备上才会显示。
  现在有不少App为了达到很华丽的视觉效果,会需要在界面上层叠很多的视图组件,但是这会很容易引起性能问题。如何平衡Design与Performance就很需要智慧了。大多数手机的屏幕刷新频率是60hz,如果在1000/60=16.67ms内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。丢帧越多,用户感受到的卡顿情况就越严重。

 -- Android性能优化详解- https://blog.csdn.net/shangmingchao/article/details/78724145
Android 系统性能优化(11)---UC性能优化方案- https://blog.csdn.net/zhangbijun1230/article/details/79674971
Android App 反应卡顿,从技术上将就是UI 渲染慢和代码执行耗时。
 一、性能优化六项指标:
  性能、内存、稳定性、流量、电量、安装包大小;
 二、背景 ---- Android程序卡顿产生原因:
   1、Android系统低效
     --渲染线程、同步接口、广播机制;
      没有独立的渲染线程;广播机制引入,可能同时又几百个广播机制在后台运行;
   2、运行环境恶劣
     --后台进程、安全软件
   3、低端机占比高
     --低内存、弱cpu、IO瓶颈:开源平台,导致高中低端的机型普遍存在;低内存影响最大,一般可用内存在小于50M,意味着会由于小于50M就会杀死一些进程来维护内存的大小;GPU是其次;读写速度比较慢,在有的手机上;
   4、产品考虑不足
    --功能定义简陋、功能堆积严重:一般的产品只会考虑需求,我要做什么,而并没有把整个闭环考虑清楚;在版本迭代的过程,在不注意间可能启动过程会越来越慢;
  5、技术考虑不足
 三、用户反馈应用卡顿怎么办?
   困难:
   1、复现性
     -- 用户描述模糊、不稳定出现(复现率比较低);
   2、定位难
     -- 不同机型、固件、系统状态表现不一
     --程序细节多、可疑面广
   3、衡量难
     -- 卡顿严重程度难以量化
     -- 卡顿问题不便分类:是有一点卡、非常卡、还是什么;没有针对性的目标,提升百分之多少等等,不知道极限在哪里;
 四、解决思路
  1、卡 vs 顿,卡为主,顿为辅。卡和顿没有一个明显的界限,大部分顿的问题当环境足够恶劣时就会表现为卡。所以抓住卡,就能解决很多问题。 
  2、打点统计 vs 全局监控:
               短期目标:主路径性能保障,打点统计;
               长期目标:整体的卡顿优化,全局监控;
  3、 线下分析 vs 线上监控:
   线下分析:实验室调试去复现一个问题,精确定位、粒度细;线上监控:指标衡量、粒度粗。 
  4、打点统计分析:
     1)、启动速度;(2)、响应速度;(3)、版本比对,app版本、Android版本;
  5、用户反馈分析:
    将用户性能方面的反馈,测试人员进行分析,以邮件形式发送给技术负责人,进行分析;
     反馈等级: --预警机制;--用户分类;--功能分类;-- 纵向对比;
  6、anr日志分析:
   --精确定位 : 堆栈信息比较清晰 ;--数据量化:主线程超时(5s ---> 1s);-- 暴漏更多蕾体;
   -- 精确定位问题;-- 方便用户联调;-- 如果一个按钮响应时间超过800ms,用户感知起来就会很难受了。
  7、全局监控 -- Looper Hook; -- 监测系统消息循环;--计算消息耗时; -- 定位耗时点;
   卡顿:无非就是主线程被卡住了,就是主线程的消息循环里面的某一帧执行时间非常长,导致后续的消息无法来得及执行,
             数据指标卡顿率: 卡顿用户数/日活总数
  8、 问题回顾:
   -- 下载界面展开卡顿: 分段加载;
   -- 二维码界面展示慢: 延时加载、先出界面在初始化相机;
   -- 启动完成后操作卡: 线程枪战,低优先级后台进程+队列;
   -- 共享存储卡顿: sharedPerference( 主线程IO , commit(主) ---> apply(子));
   -- 视频播放控制卡顿(API兼容性问题,异步化,视频播放停止暂停线程);
   -- 获取网络代理卡顿(IPC异常【进程间通信】,异步DNS+缓存);
   -- 第三方反馈卡死(固件问题,shield Activity,全部采用一个新的activity去做,这样不会对原来activity产生影响);
   --  网页滑屏操作卡顿(GPU加速 开启硬件加速);
   -- So加载/jni注册卡(异步加载 + 时序控制);
   -- 安全软件事件拦截(沟通反馈);
   --微信卡顿(调频、文件系统优化);

 五、经验推广:
   禁止:
    -- 主线程文件IO(标记文件读写外); -- 主线程耗CPU操作; -- 主线程同步IPC调用(时间不可预期);
   推荐:
   -- 异步化
            【1】、 产品及程序设计 : 加载肯定是需要时间的,不可能实时展现;
            【2】、预加载 (数据必备,功能执行之前将这些事先数据准备好)
            【3】、闲时加载: 利用cpu的闲时做一些事情,主线程会设置一个ido handler,主线程所有消息操作完成之后会回调一个handler
            【4】、按需加载
   -- 线程管理:1、线程量限制 + 任务队列;2、非主线程优先级调低;
   --压力测试; -- 防御式编程; -- 全局性能检测;
 六、延伸
  -- 精确化 & 自动化:用户反馈、卡顿日志
  -- 新监控方案:Api Hook
  -- 新优化方案:卡顿率 --> 帧率;低端机优化;

> 电量优化
Android性能优化系列之电量优化- http://blog.csdn.net/u012124438/article/details/74617649
电量分析工具Battery Historian- https://github.com/google/battery-historian
Android性能优化之电量篇- http://hukai.me/android-performance-battery/
关于网络请求引起无线信号的电量消耗,还可以参考这里http://hukai.me/android-training-course-in-chinese/connectivity/efficient-downloads/efficient-network-access.html
关于JobScheduler的更多知识可以参考- http://hukai.me/android-training-course-in-chinese/background-jobs/scheduling/index.html
  一个最简单的唤醒手机的方法是使用PowerManager.WakeLock的API来保持CPU工作并防止屏幕变暗关闭。这使得手机可以被唤醒,执行工作,然后回到睡眠状态。知道如何获取WakeLock是简单的,可是及时释放WakeLock也是非常重要的,不恰当的使用WakeLock会导致严重错误。例如网络请求的数据返回时间不确定,导致本来只需要10s的事情一直等待了1个小时,这样会使得电量白白浪费了。这也是为何使用带超时参数的wakelock.acquice()方法是很关键的。
  从Android 5.0开始发布了Battery History Tool,它可以查看程序被唤醒的频率,又谁唤醒的,持续了多长的时间,这些信息都可以获取到。
   传递网络数据de Prefetch(预取)与Compressed(压缩)技术.为了避免我们的应用程序过多的频繁消耗电量,我们需要学习如何把后台任务打包批量,并选择一个合适的时机进行触发执行。
  在Android里面一个相对操作比较繁重的事情是对Bitmap进行旋转,缩放,裁剪等.对于大多数应用中的动画,我们会使用PropertyAnimation或者ViewAnimation来操作实现.

-- 如何优化Wear的性能与电量:
  仅仅在真正需要刷新界面的时候才发出请求;
  尽量把计算复杂操作的任务交给Phone来处理;
  Phone仅仅在数据发生变化的时候才通知到Wear;
  把零碎的数据请求捆绑一起再进行操作;

-- 执行延迟任务,通常有下面三种方式:
  1)AlarmManager
使用AlarmManager设置定时任务,可以选择精确的间隔时间,也可以选择非精确时间作为参数。除非程序有很强烈的需要使用精确的定时唤醒,否者一定要避免使用他,我们应该尽量使用非精确的方式。
  2)SyncAdapter
我们可以使用SyncAdapter为应用添加设置账户,这样在手机设置的账户列表里面可以找到我们的应用。这种方式功能更多,但是实现起来比较复杂。我们可以从这里看到官方的培训课程:http://developer.android.com/training/sync-adapters/index.html
  3)JobSchedulor
这是最简单高效的方法,我们可以设置任务延迟的间隔,执行条件,还可以增加重试机制。

-- Android性能优化之电量篇
  电量消耗的计算与统计是一件麻烦而且矛盾的事情,记录电量消耗本身也是一个费电量的事情。唯一可行的方案是使用第三方监测电量的设备,这样才能够获取到真实的电量消耗。
  使用WakeLock或者JobScheduler唤醒设备处理定时的任务之后,一定要及时让设备回到初始状态。每次唤醒蜂窝信号进行数据传递,都会消耗很多电量,它比WiFi等操作更加的耗电。
  Battery Historian是Android 5.0开始引入的新API

-- 通常情况下,使用3G移动网络传输数据,电量的消耗有三种状态:
  1.Full power: 能量最高的状态,移动网络连接被激活,允许设备以最大的传输速率进行操作。
  2.Low power: 一种中间状态,对电量的消耗差不多是Full power状态下的50%。
  3.Standby: 最低的状态,没有数据连接需要传输,电量消耗最少。

  总之,为了减少电量的消耗,在蜂窝移动网络下,最好做到批量执行网络请求,尽量避免频繁的间隔网络请求。另外WiFi连接下,网络传输的电量消耗要比移动网络少很多,应该尽量减少移动网络下的数据传输,多在WiFi环境下传输数据。
-- 使用Job Scheduler的一段简要示例,需要先有一个JobService:
public class MyJobService extends JobService {
    private static final String LOG_TAG = "MyJobService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(LOG_TAG, "MyJobService created");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "MyJobService destroyed");
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        // This is where you would implement all of the logic for your job. Note that this runs
        // on the main thread, so you will want to use a separate thread for asynchronous work
        // (as we demonstrate below to establish a network connection).
        // If you use a separate thread, return true to indicate that you need a "reschedule" to
        // return to the job at some point in the future to finish processing the work. Otherwise,
        // return false when finished.
        Log.i(LOG_TAG, "Totally and completely working on job " + params.getJobId());
        // First, check the network, and then attempt to connect.
        if (isNetworkConnected()) {
            new SimpleDownloadTask() .execute(params);
            return true;
        } else {
            Log.i(LOG_TAG, "No connection on job " + params.getJobId() + "; sad face");
        }
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        // Called if the job must be stopped before jobFinished() has been called. This may
        // happen if the requirements are no longer being met, such as the user no longer
        // connecting to WiFi, or the device no longer being idle. Use this callback to resolve
        // anything that may cause your application to misbehave from the job being halted.
        // Return true if the job should be rescheduled based on the retry criteria specified
        // when the job was created or return false to drop the job. Regardless of the value
        // returned, your job must stop executing.
        Log.i(LOG_TAG, "Whelp, something changed, so I'm calling it on job " + params.getJobId());
        return false;
    }

    /**
     * Determines if the device is currently online.
     */
    private boolean isNetworkConnected() {
        ConnectivityManager connectivityManager =
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return (networkInfo != null && networkInfo.isConnected());
    }

    /**
     *  Uses AsyncTask to create a task away from the main UI thread. This task creates a
     *  HTTPUrlConnection, and then downloads the contents of the webpage as an InputStream.
     *  The InputStream is then converted to a String, which is logged by the
     *  onPostExecute() method.
     */
    private class SimpleDownloadTask extends AsyncTask<JobParameters, Void, String> {

        protected JobParameters mJobParam;

        @Override
        protected String doInBackground(JobParameters... params) {
            // cache system provided job requirements
            mJobParam = params[0];
            try {
                InputStream is = null;
                // Only display the first 50 characters of the retrieved web page content.
                int len = 50;

                URL url = new URL("https://www.google.com");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setReadTimeout(10000); //10sec
                conn.setConnectTimeout(15000); //15sec
                conn.setRequestMethod("GET");
                //Starts the query
                conn.connect();
                int response = conn.getResponseCode();
                Log.d(LOG_TAG, "The response is: " + response);
                is = conn.getInputStream();

                // Convert the input stream to a string
                Reader reader = null;
                reader = new InputStreamReader(is, "UTF-8");
                char[] buffer = new char[len];
                reader.read(buffer);
                return new String(buffer);

            } catch (IOException e) {
                return "Unable to retrieve web page.";
            }
        }

        @Override
        protected void onPostExecute(String result) {
            jobFinished(mJobParam, false);
            Log.i(LOG_TAG, result);
        }
    }
}
  然后模拟通过点击Button触发N个任务,交给JobService来处理
public class FreeTheWakelockActivity extends ActionBarActivity {
    public static final String LOG_TAG = "FreeTheWakelockActivity";

    TextView mWakeLockMsg;
    ComponentName mServiceComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wakelock);

        mWakeLockMsg = (TextView) findViewById(R.id.wakelock_txt);
        mServiceComponent = new ComponentName(this, MyJobService.class);
        Intent startServiceIntent = new Intent(this, MyJobService.class);
        startService(startServiceIntent);

        Button theButtonThatWakelocks = (Button) findViewById(R.id.wakelock_poll);
        theButtonThatWakelocks.setText(R.string.poll_server_button);

        theButtonThatWakelocks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    pollServer();
            }
        });
    }

    /**
     * This method polls the server via the JobScheduler API. By scheduling the job with this API,
     * your app can be confident it will execute, but without the need for a wake lock. Rather, the
     * API will take your network jobs and execute them in batch to best take advantage of the
     * initial network connection cost.
     *
     * The JobScheduler API works through a background service. In this sample, we have
     * a simple service in MyJobService to get you started. The job is scheduled here in
     * the activity, but the job itself is executed in MyJobService in the startJob() method. For
     * example, to poll your server, you would create the network connection, send your GET
     * request, and then process the response all in MyJobService. This allows the JobScheduler API
     * to invoke your logic without needed to restart your activity.
     *
     * For brevity in the sample, we are scheduling the same job several times in quick succession,
     * but again, try to consider similar tasks occurring over time in your application that can
     * afford to wait and may benefit from batching.
     */
    public void pollServer() {
        JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        for (int i=0; i<10; i++) {
            JobInfo jobInfo = new JobInfo.Builder(i, mServiceComponent)
                    .setMinimumLatency(5000) // 5 seconds
                    .setOverrideDeadline(60000) // 60 seconds (for brevity in the sample)
                    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // WiFi or data connections
                    .build();

            mWakeLockMsg.append("Scheduling job " + i + "!\n");
            scheduler.schedule(jobInfo);
        }
    }
}

> APP耗电量/流量与优化
Android APP性能优化的四个方面最全总结- https://blog.csdn.net/zhangbijun1230/article/details/79449725
-- 电量
Android5.0之后电量优化的工具battery-historien- https://github.com/google/battery-historian
 随着Android6.0更新了Battery Historian 2.0加入引起手机状态变化的应用。Android系统上App的电量消耗主要由cpu、wakelock、数据传输(流量和wifi)、wifi运行、gps、other senior组成,而耗电异常也是由于这几个模块的使用不当。
-- 监听电池充电操作
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = this.registerReceiver(null, filter);

//几种充电方式:直流充电,USB充电,无线充电
    int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        boolean usbCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_USB);
        boolean acCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_AC);
        boolean wirelessCharge = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            wirelessCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_WIRELESS);
        }
        return (usbCharge || acCharge || wirelessCharge);
    }

Android应用耗电量分析与优化建议- https://www.jianshu.com/p/ebac88cdf9d6
Android APP耗电优化的一些经验- https://blog.csdn.net/tomatomas/article/details/53450364
 adb shell dumpsys batterystats adb shell dympsys batterystats > D:/batterystats.txt
深入浅出Android App耗电量统计- https://blog.csdn.net/yinjian1013/article/details/78932725
Android性能优化(九)之不可忽视的电量- https://www.jianshu.com/p/5d83d8649c98
Android App优化之电池省着用- https://www.jianshu.com/p/c55ef05c0047

-- 流量
 增量升级功能实现APK的更新。
android获取自己app消耗的流量- https://blog.csdn.net/baidu_31093133/article/details/79370844
Android性能优化(八)之网络优化- https://www.jianshu.com/p/d5a843cb7ab1
  Facebook的开源项目augmented-traffic-control可以模拟不同的网络环境,针对带宽、时延抖动、丢包率、错包率、包重排序率等方面,堪称弱网调试神器;
Android App优化之网络优化- https://www.jianshu.com/p/d4c2c62ffc35
APP开发实战120-APP网络流量优化- https://blog.csdn.net/xjbclz/article/details/52028848

> 网络优化
Android性能优化- https://github.com/Shimingli/PerformanceOptimizationForAndroid
Android性能优化-电量优化,布局优化和网络优化- https://blog.csdn.net/liuwei187/article/details/78958363
android 网络框架性能优化分析- https://blog.csdn.net/hhlin1/article/details/50708346
从用户的角度分析,我们优化的目标就是,如何实现以最少流量,最少电量,最少内存以及最快速度获取到服务端数据。
Android性能优化(八)之网络优化- https://www.aliyun.com/jiaocheng/18291.html
Android性能优化- https://www.jianshu.com/p/8301af3a2902
  网络优化主要从三个方面进行:1. 速度;2. 成功率;3. 流量
 Gzip压缩;IP直连与HttpDns;图片处理(三级缓存,下载与缓存);协议层的优化;请求打包,合并网络请求,连接复用;网络缓存;数据的增量更新 
  流量耗费;电量消耗;用户体验差

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值