Android内存优化

1.节制的使用Service,最好使用IntentService(任务结束会自动停止,避免Service内存泄漏),只有当任务正在执行的时候才让Service运转起来

2.避免创建不必要的对象(StringBuilder和String)

3.对常量使用static final修饰

4.使用增强型for循环语法(ArrayList除外),传统for循环的第二布尽可能简洁

5.重用布局文件,include,

merge(减少布局嵌套层数),

merge标签可用于两种典型情况:

  • 布局根结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容布局的parent view就是个FrameLayout,所以可以用merge消除只剩一个,这一点可以从上图中看到。

  • 某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。

ViewStub,它就是一个占位符,它在布局中不占用空间,自然inflate的时候它也不消耗资源。只有当调用ViewStub的inflate的时候才会用布局替代它,用于提高布局效率,不过使用范围很窄:ViewStub只能被inflate一次,之后就无效了不能再引用它。一般用在onCreate的时候,决定布局里面哪个部分显示,哪个不显示,可以使用ViewStub,并且只能用来Inflate一个布局文件,而不能Inflate某个具体的View。(按需加载,View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();  importPanel.findViewById())
6.Bitmap(内存消耗大户):

在实例化Bitmap的代码中,一定要对OutOfMemory异常进行捕获,出现异常得到一个默认的bitmap图;

缓存通用的Bitmap对象

有时候,可能需要在一个Activity里多次用到同一张图片。比如一个Activity会展示一些用户的头像列表,而如果用户没有设置头像的话,则会显示一个默认头像,而这个头像是位于应用程序本身的资源文件中的。

如果有类似上面的场景,就可以对同一Bitmap进行缓存。如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。

 内存缓存(LruCache ,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除,在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。)另外传入 LruCache 的键值对不能是 null。

Lrucache:LRU即Least Recently Used,近期最少使用算法。也就是当内存缓存达到设定的最大值时将内存缓存中近期最少使用的对象移除,有效的避免了OOM的出现。Lru算法的实现就是通过LinkedHashMap来实现的。LinkedHashMap继承于HashMap,它使用了一个双向链表来存储Map中的Entry顺序关系,这种顺序有两种,一种是LRU顺序,一种是插入顺序LruCache中将LinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get(也就是从内存缓存中取图片),则将该对象移到链表的尾端。调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。

补充:LruMemoryCache代码和v4包的LruCache一样,只是加了一个存储超期的处理


硬盘缓存(DiskLruCache,通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data/<application package>/cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。)

DiskLruCache移除缓存:remove()方法中要求传入一个key,然后会删除这个key对应的缓存图片。这个方法我们并不应该经常去调用它。因为你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题,DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。每当版本号改变,缓存路径下存储的所有数据都会被清除掉,因为DiskLruCache认为当应用程序有版本更新的时候,所有的数据都应该从网上重新获取


图片显示按需加载,图片大小进行缩放(设置inJustDecodeBounds参数和BitmapFactory.Options的采样率),,图图片像素进行处理(RGB_565会比使用ARGB_8888少消耗2倍的内存)片回收(生成Bitmap对象的BitmapFactory的四类方法最终都是在安卓底层实现的,对应着BitmapFactory类的几个native方法,最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存里以后,是包含两部分内存区域的:Bitmap对象存储在Dalvik heap中,而Bitmap对象的像素数据则存储在Native Memory(本地内存),由Java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。最初需要调用recycle()方法来释放C部分的内存,安卓3.0以后,Bitmap的像素数据和Bitmap对象一起存储在Dalvik heap中,系统会自动释放

补充:BitmapFactory.Options.inBitmap的这个字段,假如这个字段被设置了,我们在解码Bitmap的时候,他会去重用inBitmap设置的Bitmap,减少内存的分配和释放,提高了应用的性能

7.避免内部调用get,set(字段搜寻比方法调用效率高)

8.减少APK大小

9.能用基本类型如Int,Long,就不用Integer,Long对象,基本类型变量占用的内存资源比相应对象占用的少得多

10.避免内存泄漏     

Android内存泄露抓取工具leakcanary (leakcanry在application中配置,它通过弱引用方式侦查Activity或对象的生命周期,若发现内存泄露得到泄露的最短路径,最后通过notification展示。)        

非静态内部类的静态实例容易造成内存泄1.将内部类变成静态内部类 2.如果有强引用Activity中的属性,则将该属性的引用方式改为弱引用。3.在业务允许的情况下,当Activity执行onDestory时,结束这些耗时任务。

activity使用静态成员,单例模式,静态变量持有activity的context的引用(不使用的时候显示设置为null或者持有applicationcontext的引用)

-bitmap的回收

使用handler时的内存问题(onDestroy时清除消息,mHandler.removeCallbacksAndMessages(null);handler设为静态内部类,并设置为对activity的弱引用)

注册某个对象后未反注册

集合中对象没清理造成的内存泄露

资源对象没关闭造成的内存泄露

构造Adapter时,没有使用缓存的 convertView

兜底回收 在Activity onDestory时候从view的rootview开始,递归释放所有子view涉及的图片,背景,DrawingCache,监听器等等资源,让Activity成为一个不占资源的空壳,泄露了也不会导致图片资源被持有。


补充:绝大多数情况下,硬件加速可以解决莫名的卡顿问题,设置android:hardwareAccelerated="true"可为activity开启硬件加速



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值