Android学习笔记:Android优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/MaybeForever/article/details/100046477

一、如何处理网络图片产生的OOM异常?

常见的OOM异常主要是由程序中图片过多过大引起的。为了避免在加载图片过程中导致的OOM问题,一般不建议直接加载原始图片。

  • 1、调整图片大小(压缩图片)
    每个Android手机屏幕尺寸有限,分配给图像的显示区域本身也就更小,图像大小可以适当调整。
    在程序中,调整图片的大小需要通过设置Options的inJustDecodeBounds属性true,将图片的width和height属性读取出来。我们可以利用这些属性对Bitmap进行压缩,同时通过Options.inSampleSize属性可以设置图片的压缩比。

  • 2、及时回收不用的图片资源
    及时回收不用的图片资源,如果引用了大量的Bitmap对象,而应用中又不需要同时显示所有图片,因此可以将暂时不用的Bitmap对象及时回收掉。回收Bitmap对象的具体代码如下:

    public void releaseImage(){
    	if(null != bitmap){
    		bitmap.recycle();
    		bitmap = null;
    	}
    }
    
  • 3、缓存图片到内存中(内存对象重复利用)
    在Android应用程序中,有一个LruCache类专门用于处理图片缓存。该类的一个特点是当缓存的图片达到了预先设定的值时,则该类内部会根据最近最少使用的算法,移除最近使用次数最少的图片,以达到防止OOM溢出的目的。这个预先设定的值是允许当前内存分配给图片使用的最大内存空间,这个内存空间的大小是根据项目实际需求自行定义的,但一般设置为内存的1/8。
    获取应用内存的大小的具体代码如下:

    int MAXMEMONRY = (int)(Runtime.getRuntime().maxMemory()/1024);
    

二、布局优化

布局优化的思路就是尽量减少布局文件的层级。

  • 1、删除布局中无用的控件和层级
    例如:1)抽取布局中的相同部分;2)去除不必要的嵌套和View结点);

  • 2、有选择地使用性能较低的ViewGroup

  • 3、< merge >标签的使用
    适当的使用< merge >标签,可以减少多余的布局嵌套,提高界面填充速度;

  • 4、使用ViewStub实验延迟加载
    ViewStub是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件;

三、绘制优化

绘制优化是指View的onDraw方法要避免执行大量的操作。

  • 1、onDraw中不要创建新的局部对象
    如果OnDraw方法被频繁调用,会在一瞬间产生大量的临时对象,增加GC负担并且降低了程序的执行效率。

  • 2、onDraw方法中不要做耗时的任务
    注意:Google官方给出的性能优化典范中的标准,View的绘制频率保证60fps是最佳的,这就要求每帧的绘制时间不超过16ms(16ms = 1000 / 60)

四、内存泄漏优化

内存泄漏的根本原因:长生命周期的对象持有短生命周期的对象,短生命周期的对象就无法及时释放。

内存泄漏优化分为两个方面:①在开发过程中避免写出有内存泄漏的代码;②通过一些分析工具比如MAT(或DDMS-Heap)来找出潜在的内存泄漏继而解决。(通过DDMS的Heap视图可以很容易的发现程序中是否存在内存泄漏,而通过MAT工具可以具体定位问题所在。

其中,针对①出路内存泄漏又可以引申出以下5点:

  • 1、使用单例模式
    当创建一个单例时,如果传递的是Activity的Context,则该Context与Activity的生命周期一样长。由于单例对象持有该Activity的引用,因此当该Activity退出时它的内存并不会被回收,容易引起内存泄漏。如果传递Application的Context,则单例对象的生命周期和Application一样长,就不会出现内存泄漏的问题。

  • 2、避免在非静态内部类中创建静态实例
    在Java中,如果在非静态内部类中创建静态实例,则该非静态内部类会持有外部类的隐式引用,如果存储该引用,则会导致对于的Activity不被垃圾回收机制回收。若将该内部类设为静态内部类或抽取出来封装成一个单例,则不会出现内存泄漏问题。

  • 3、及时关闭不使用的对象
    当不使用资源性对象如Cursor、File文件时,需要及时关闭,以便及时回收他们所占用的内存。如果仅仅把他们的引用设置为null,而不关闭它们,就容易造成内存泄漏。

  • 4、及时回收ThreadLocal绑定的对象
    当不再使用ThreadLocal时,我们需要调用remove()或set(null)方法使ThreadLocal绑定的对象能及时被回收,避免产生内存泄漏的问题。

  • 5、及时回收内存与有效利用已有对象
    在Android开发过程中,对于没有及时回收的内存,或是没有有效利用已有的对象,则容易造成内存泄漏。

五、响应速度优化

响应速度优化的核心思想是避免在主线程中做耗时操作。

解决方法:将这些耗时的操作放在线程中去执行,即采用异步的方式执行耗时操作。

注:Android规定,Activity如果5秒钟之内无法响应屏幕触摸事件或者键盘输入时间就会出现ANR;而BroadcastReceiver如果10秒钟之内还未执行完操作也会出现ANR。

六、ListView优化

  • 1、复用convertView
    在getView()方法中,系统提供了一个复用View的历史缓存对象convertView,为了节约内存,可以在convertView不为null的时候对其进行复用;

  • 2、定义存储控件引用类ViewHolder
    将要加载的子View放在ViewHolder类中,当第一次创建convertView时将这些控件找出,在第二次重用convertView时便可直接通过convertView中的getTag()方法获得这些控件;

  • 3、根据列表的滑动状态来控制任务的执行频率
    频繁滑动会带来大量的UI更新操作(无意义的),而这些UI操作是运行在主线程的,就会造成一定程度的卡顿。因此,可以考虑在列表滑动的时候停止加载图片,等列表停下来以后再加载图片仍可以获得良好的用户体验。

  • 4、尝试开启硬件加速来使ListView的滑动更加流畅

  • 5、数据的分批及分页加载
    1)分批加载:主要是把每次请求服务器返回的固定条数的数据显示在ListView的页面中。当列表下拉到底部时,会获取一批数据显示到界面上;
    2)分页加载:固定每页需要加载数据的条数,然后把每页获取的数据显示到界面上;
    3)总结:二者原理相同,并且都优化了内存空间,不同在于分批加载需要判断ListView是否下拉至底部,然后加载数据,有个刷新过程;

  • 6、图片的处理
    如果在自定义Item中涉及图片,一定要对图片进行优化。优化图片的方法如下:
    1)要用WeakReference(使用WeakReference代替强引用)来存储与获取图片信息。
    2)当获取图片的时,要对图片进行边界压缩才能存放到内存中。
    3)在getView()方法中做图片转换时,产生的中间变量一定要及时释放。

七、线程优化

线程优化的思想是采用线程池,避免程序中存在大量的Thread。

解决方法:线程池可以重用内部的线程,从而避免了线程的创建和销毁所带来的性能开销,同时线程池还能有效地控制线程池的最大并发数,避免大量线程因互相抢占系统资源从而导致阻塞现象的发生。

八、如何避免内存泄露(待整理)

1、减小对象的内存占用:
(1)使用更加轻量级的数据结构:
考虑适当的情况下替代HashMap等传统数据结构而使用安卓专门为手机研发的数据结构类ArrayMap/SparseArray。SparseLongMap/SparseIntMap/SparseBoolMap更加高效。
HashMap.put(string,Object);Object o = map.get(string);会导致一些没必要的自动装箱和拆箱。
(2)适当的避免在android中使用Enum枚举,替代使用普通的static常量。(一般还是提倡多用枚举—软件的架构设计方面;如果碰到这个枚举需要大量使用的时候就应该更加倾向于解决性能问题。)。
(3)较少Bitmap对象的内存占用。
使用inSampleSize:计算图片压缩比例进行图片压缩,可以避免大图加载造成OOM; decodeformat:图片的解码格式选择,ARGB_8888/RGB_565/ARGB_4444/ALPHA_8,还可以使用WebP。
(4)使用更小的图片
资源图片里面,是否存在还可以继续压缩的空间。

2、内存对象的重复利用:
使用对象池技术,两种:1.自己写;2.利用系统既有的对象池机制。比如LRU(Last Recently Use)算法。
(1) ListView/GridView源码可以看到重用的情况ConvertView的复用。RecyclerView中Recycler源码。
(2)Bitmap的复用
Listview等要显示大量图片。需要使用LRU缓存机制来复用图片。
(3)避免在onDraw方法里面执行对象的创建,要复用。避免内存抖动。
(4)常见的java基础问题—StringBuilder等
3、避免对象的内存泄露
4、使用一些内存的优化策略

猜你喜欢

转载自blog.csdn.net/MaybeForever/article/details/100046477