前言:首先感谢这两天大家的投票,SuperVideo将不再拉票,可以去魅族应用市场下载最新2.0版本私下体验。有想帮投的,上一篇文章中,有链接。尤其感谢鸿洋基友和明云基友,两位都有维护自己的公众号和博客,没有关注鸿洋公众号和明云的open dev公众号的,文章下面有二维码,可关注。鸿洋,一直更新着公众号,不管刮风还是下雪,工作日每天7:30准时推送一篇干货。csdn博客早已突破千万:blog地址为:http://blog.csdn.net/lmj623565791,做Android的,不用我说,应该都知道。明云(张明云),知乎专栏上写了一系列的性能优化,都相当实用,open dev也会定期送上干货,不定期汇总推荐当下优秀文章)今天来看下

杨超凡授权本公众号的Google官方的性能优化一些优化建议:点击阅读原文,可查看

杨超凡的原文:http://blog.csdn.net/chivalrousman/article/details/51553114,话不多说,看下正文。

1

使用AsyncTask加载Bitmap

当图片资源来自网络或者硬盘的时候,最好不要直接在主线程中加载它,例如IO资源或者数据库资源都会占用CPU,CPU 要做的事情过多,Android手机会造成卡顿得现象,好在Google 提供了解决办法–AsyncTask异步加载工具


接着我们在主线程中执行它即可

2

使用Lrucache缓存图片

1. 为什么要缓存图片?

对于如何高效的加载一张图片 ,我们似乎已经得心应手了,这里要泼一盆凉水给大家,因为我们的应用不仅只是加载一张图片这么简单,比如ListView, GridView or ViewPager,RecyclerView,需要立刻加载出大量的bitmap,滑动的过程不断加载bitmap,还要求不卡顿,内存够用,这似乎又是一件棘手的事情。

Google 又提供了一种解决思路:对于ListView,RecyclerView,有可见的item和不可见的item,回收不可见的item 内存,分配给可见的,这样内存得到了重复利用,避免重复创建对象,不断申请并分配新的内存空间,触发最低内存限制的危险。

所以我们要管理 这些 已经创建好的内存。

2. 使用内存缓存

  1. 为什么优先使用内存缓存?

    答:相比硬盘缓存的读取速度,读取内存中的数据更快

  2. Google官方有什么建议?

    答:Google推荐Lrucache类,底层使用用强引用封装的LinkedHashMap,来存储最近使用的对象,它自动会回收最近使用的对象当中,使用的最少的那一个对象的内存,这一点毋庸置疑值得推荐!

一种过时的做法,是用虚引用或者弱引用来标记bitmap,这种方法在Android 3.0以后已经不提倡了,因为类似JDK1.8那样,bitmap的内存是放在本地内存中的,它的回收是不确定的,有可能导致APP挂掉,切勿使用。

  1. Lrucache这么棒,我们该如何用?

    Lrucache就可以当作一种存储数据的结构,类似list,set,可以存储对象,获取对象,对应的有add() 和get()方法,它与数组一样,初始化的时候需要指定一个初始的大小。

    那么Lrucache实例 初始的大小该如何确定? 
    在计算大小之前,我们需要明确几件事情:

  • 我们的Activity和Application还有多少可用内存?

  • 第一次加载的时候,需要为多少图片分配内存?可见的item数量,决定了图片的数量,图片的数量*每张图片的内存大小就是初始化需要分配的内存。

  • 用户当前手机的屏幕尺寸和屏幕密度(为什么要这俩参数?大屏幕手机 ,初始化的时候会加载更多的item,需要的内存更大)

  • 这张图片我们要怎样配置?图片的尺寸如何设置,颜色模式如何配置?根据不同的需求,比如是做用户头像,还是信息展示?都有各自的应用场景的要求。我们需要分类判断.

  • cache大小是由内存大小决定的,而不是 它存储数据的个数决定

    这让我想起一个在项目开发中常见的bug,use a bitmap which has bean recycler

3. Lrucache使用实例

loadBitmap的过程很简洁:如果内存缓存中有这张bitmap,则直接刷新imageview,如果bitmap为空,则启动后台线程去加载bitmap,接着刷新imageview


异步线程 BitmapWorkerTask


4. 磁盘缓存

与内存缓存相结合的还有磁盘缓存,虽然磁盘读取速度较慢,但是持久存储的,不像内存缓存那样,在内存极限情况下仍然会被清理,比如后台正在执行数据加载,突然打进来一个电话,内存不足系统可能会进行垃圾回收。缓存就没有了

Google官方提供直接DiskLruCache 类

为什么要使用DiskLruCache 很明了:就是解决当内存缓存不可用的情形

内当需要频繁访问缓存的图片资源时,比如APP的画廊功能,可以考虑使用ContentProvider解决更为妥当。

5.处理运行时变更的缓存

当屏幕旋转,或者其他原因导致Activity restart,这个时候难道又让我们重新创建大量的图像资源? 
回答是否定的,Google提供了一种解决方案:

通过在Activity中使用fragment,构造Fragment时,通过设置 setRetainInstance(true))来设置缓存, 
话不多说,直接上代码:

3

RecyclerView GridView ListView


下面可能是大家经常的做法:

看上去非常棒,对吗?但是我们如何才能做的更好?

如果你能发现主线程加载图片的问题,恭喜你,有一点点进步。但是重复提醒你使用AsyncTask,显然不是我写这一节的目的。

我们还需要警惕GridView 中的并发问题,因为iGridView 会回收子View的内存空间。

并发问题

像ListView和GridView,与RecyclerView使用AsyncTask的时候,不能忽视一个问题:Android系统为了高效分配内存,这些组件都会在上下滑动的时候回收子view的内存。在滑动的时候,并不能保证AsyncTask可以完成当前任务。此外,也不能保证异步任务可以按照顺序完成。

Google在 Multithreading for Performance 提供了建议:在AsyncTask中,用弱引用来存储ImageView,通过使用弱引用来被检查ImageView是否加载完成

好吧,理论上是这样,我们开始行动:

1. 自定义Drawable去存储异步任务重的弱引用,只有这样,才能保证task执行完毕之后,ImageView才会显示图片

2. 在执行BitmapWorkerTask之前,你需要创建 AsyncDrawable 并且绑定到ImageView上,通过如下代码:

3. 仅仅这些代码还是不够的,Google 还引入 cancelPotentialWork()来检查是否有其他的task任务在使用当前ImageView,如果有,就会取消当前任务,取消这个做法是不是很让人眼前一亮呢!

这是cancelPotentialWork()的实现


4. 我们还需要get方法获得相关的ImageView:


5. 最后就是更新task中的onPostExecute()检查任务是否取消:


至此,我们已经了解Google 对于并发加载的解决方案,只需要在getView()实现它们就可以啦!

在GridView解决并发



这样解决并发的办法,同理适用于ListView, Recycler 
这也是热门加载框架ImageLoader,Volley 的加载原理。原理还是Google提出的!

这样就可以流畅的展示图片。

4

View Holder设计模式

我们的代码可能会调用findViewById(),尤其是当滑动ListView,RecyclerView,GridView的时候,会使得app性能变得糟糕。甚至Adapter会返回一个已经被Android系统回收的View,可是你仍然需要初始化加载这个view并刷新它。

Google提出了使用 “View Holder” 设计模式

1. 首先创建 ViewHolder类,存储子View内部所有需要展示的布局


2. 接着填充ViewHolder并且存储到布局中


‘view holder’ 设计模式同样也适用于ListView,RecyclerView,GridView

关注鸿洋微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

关注open Dev微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

Google官方 详解 Android 性能优化【史诗巨著之内存篇】相关推荐

  1. Google官方 详解 Android 性能优化【史诗巨著之内存篇】

    尊重博主原创,如需转载,请附上本文链接http://blog.csdn.net/chivalrousman/article/details/51553114#t16 为什么关注性能 对于一款APP,用 ...

  2. 详解 Android 性能优化

    为什么关注性能 对于一款APP,用户首先关注的是 app的性能,而不是APP本身的属性功能,用户不关心你是否是搞社交,是否搞电商,是否是一款强大的美图滤镜app,用户首先关注的是 性能--性能不好,用 ...

  3. Android 性能优化 之谈谈Java内存区域

    最近一年副业主要在学习投资和技能学习,把以前学习内存分析的一些笔记总结发出来,写了很多笔记总结都没有写完就又忙着了,最近再次总结复习学习一遍,还有提醒各位同学一定要学会投资.. 了解Android 内 ...

  4. Android 性能优化 之初识Java内存区域

    前言     不管是日常开发,还是面试,我们都会和内存打交道,因为内存是支持软件运行的基本硬件环境.了解Android 内存管理,就有必要了解Java GC机制,必须要理解JVM 内存区域,这里我们主 ...

  5. Android性能优化(2):常见内存泄漏与优化(二)

    文章目录 1. Android虚拟机:Dalvik和ART 1.1 JVM与Dalvik区别 1.2 Dalvik与ART区别 1.3 Dalvik/ART的启动流程 2. 常见内存分析工具 2.1 ...

  6. 详解Android电量优化

    目录 写在前面 一.电量优化介绍及方案选择 1.1.如何正确认识电量优化 1.2.耗电量测试方案 二.Battery Historian实战分析 三.电量辅助监控实战 3.1.获取运行时能耗 3.2. ...

  7. Android 性能优化----(3)内存优化指南

    前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录 1. 定义 优化处理 应用程序的内存使用.空间占用 2. 作用 避免因不正确使用内存 &a ...

  8. Android性能优化(二)—— 内存优化

    在Android系统中,垃圾回收是自动的,比较隐蔽,这就导致一些内存问题表现的并不明显,出现问题后难以定位.常见的内存问题有内存泄漏.内存溢出(Out of Memory).内存抖动等. 我们做内存优 ...

  9. android布局优化 工具,详解Android布局优化

    怎样才能写出优秀的Android App,是每一个程序员追求的目标.那么怎么才能写出一个优秀的App呢?相信很多初学者也会有这种迷茫.一句话来回答这个问题:细节很重要.今天我们就从最基础的XML布局来 ...

  10. DBA整理的万字详解MySQL性能优化,值得收藏!

    点击关注公众号,实用技术文章及时了解  作者:LanceToBigData  cnblogs.com/zhangyinhua/p/7620964.html 说起MySQL的查询优化,相信大家积累一堆技 ...

最新文章

  1. Java抽象类与接口的区别
  2. wxWidgets:wxTreeCtrl概述
  3. promise使用promise进行封装拉起微信支付
  4. c++ 用eclipse建立一个类,并实例化并运行
  5. 居民安装光伏系统常会碰壁 怎么样做才能少走弯路?
  6. 孙鑫MFC笔记之十七--HOOK编程
  7. testbench实例 vhdl_VHDL的testbench的编写
  8. 如何官网下载 IEEE 论文 Latex 和 Word 模板
  9. 计算机运算器由什么组成部分,运算器由哪些部分组成
  10. Probabilistic Matrix Factorization(概率矩阵分解)
  11. LaTex常用技巧7:常用网站(公式和表格编辑器)
  12. 卫星高度角和方位角的计算
  13. JS JQuery实现简单的鼠标移动动画效果
  14. ie6,ie7常见兼容性问题总结
  15. python 串口接收数据错误_PySerial无法正确接收数据
  16. 特征选择(一)-维数问题与类内距离
  17. 【语音识别】动态时间规整算法(RTW)语音识别系统【含GUI Matlab源码 341期】
  18. 云闪付和微信支付达成“条码支付互通”,二者支付功能有何不同?
  19. 最新简约虚拟资源下载站源码+织梦Dedecms内核
  20. 谈谈我对opencv中IplImage图像参数widthstep的理解

热门文章

  1. python3基本语法规则,Python中的语法规则
  2. 增加window服务器,Windows Server2012入门-添加服务器角色和功能
  3. 设计模式(2)——观察者模式
  4. C++_模板全特化、偏特化
  5. Random walk 和 random walk with Restart理解
  6. js复制json对象
  7. 工欲善其事必先利其器——开发篇
  8. 调整数组顺序使奇数位于偶数前面(剑指offer)
  9. 映射器配置文件和映射器接口
  10. 题目1471: A+B without carry