Handler优化(相关:防OOM,强、弱、软、虚引用)

1. 前言

  • 详细介绍AndroidHandler使用优化,防止OOM
  • 处理方式其实比较大众化,主要是通过这篇文章介绍下处理Handler机制OOM过程中,详细的知识点,这是一个学习的工程。
  • 本文资料来源网络公开资源,并根据个人实践见解纯手打整理,如有错误请随时指出。
  • 本文主要用于个人积累及分享,文中可能引用其他技术大牛文章(仅引用链接不转载),如有侵权请告知必妥善处理。

2. Handler机制OOM原因

  1. 非静态内部类、匿名内部类持有外部类(Activity)的引用
    非静态内部类、匿名内部类默认将斥候外部类的引用,导致被引用对象无法及时gc。
  2. 子线程或Handler持有Activity或Context的引用
    子线程或Handler声明周期同Activity不一致,如Activity已被Destory,但子线程或Handler声明周期未结束,则同样导致引用对象(Activity或Context)无法及时gc。

3. Handler机制OOM解决方式

  1. 普通的Handler写法(Handler handler = new Handler() {...}),Handler接收到消息后多数情况下需要对UI处理而持有当前Activity的引用,或其它可能影响到当前Activity中变量的情况同样也会持有当前Activity的引用。由于Handler的生命周期和当前Activity并不同步,比如延迟发送的消息,未发送回Handler时,当前Activity已被finish,已被finish的Activity因为被Handler持有引用而仍存在于内存中迟迟未被gc,这种情况累计过多将导致OOM。这种情况,需要采用弱引用保存Activity或Context。并且在Activity的onDestory,清除该Handler需要接收未接收到的通知。
  2. 内部类Handlerprivate class MyHandler extends Handler{...}),一是和1.相同将持有当前Activity的引用,二是若该类非静态内部类,将默认持有外部类的引用,这时除了需要和```1.````相同的处理,还需要定义该类为静态内部类。
  3. 如使用Thread子线程Thread thread = new Thread(new Runnable() {...});),其中若引用了当前Activity或Context,Thread同样需要静态,并且即使未引用当前Activity或Context,其匿名内部类new Runnable(){...}也需要静态非匿名(因匿名内部类默认引用外部类),同时需要和```1.````相同的处理,使用弱引用的Activity或Context。
  4. 如使用Handler的postAtTime(…)postAtTime(new Runnable() {...},5000))定时发送消息,其处理方式需要和Thread子线程相同。

4. 强引用,软引用,弱引用,虚引用

gc对引用对象的回收强度:虚引用 > 弱引用 > 软引用 > 强引用 ,前提必须是该Object对象生命周期已结束,如Activity已finish。

4.1. 强引用

可以理解为任何情况下对一个对象的持有或访问。
当一个Object object = new Object(),这个object在栈内存名为"object",指向堆内存中"new Object"这块内存(每次new一个都有单独的内存),这种普通的new对象即可以理解为强引用。
如果这个object的属性age同另一个object1的age作比较,这时也是强引用。

  • gc不主动回收强引用
  • 在多线程或其他生命周期不同的情况下,极易造成内存溢出

4.2. 软引用

  • 使用SoftReference类实现,引用Object时,通过SoftReference的get方法获得,如为null则Object已被回收

  • 软引用Object对象将在 内存溢出之前 gc进行回收

  • 如仅需要保证app不oom,多数情况使用软引用即可

  • 软引用常常可用于Drawable图片资源缓存,可以有效的避免Drawable内存过大的oom
    将Drawable加入软引用SoftReference<Drawable> drawableSoftReference = new SoftReference<Drawable>(drawable),在view展示时,调用get()获取Drawable,当内存不足时,将返回null

  • 代码示例,请注意其中注解:

    Object obj = new Object();
    SoftReference<Object> ref = new SoftReference<Object>(obj);
    
    //获取Object,已被回收则返回null
    ref.get();
    

    也可以将SoftReference加入ReferenceQueue对列,当Object被回收后,回收SoftReference对象

    Object obj = new Object();
    
    //创建对列,该队列中将会添加已被回收Object的SoftReference<Object>对象
    ReferenceQueue queue = new ReferenceQueue();
    
    SoftReference<Object> ref = new SoftReference<Object>(obj, queue);
    
    //判断SoftReference<Object>是否已被加入ReferenceQueue队列(Object是否被gc回收),
    //该方法仅在已添加ReferenceQueue的情况下有效(详见源码)
    ref.isEnqueued();
    
    //检查ReferenceQueue队列中是否有已被回收Object的SoftReference<Object>,对其回收
    SoftReference<Object> refGc = null;
    while ((refGc = (SoftReference<Object>)queue.poll()) !=null){
        refGc.clear();
    }
    

4.3 弱引用

  • WeakReference类实现
  • 弱引用Object对象将在下次gc时被回收
  • 生命周期较短的,内存占用大的对象,可以偏向于使用弱引用
  • 使用方法和软引用基本相同,SoftReference和WeakReference均是Reference的子类

4.3 虚引用

  • PhantomReference类实现

  • 弱引用Object对象将在任意gc时被回收

  • get()返回的对象永远为null,PhantomReference只用来标记该Object是否被回收,不常用

  • 代码示例,请注意其中注解:

    Object obj = new Object();
    
    //队列是必须的
    ReferenceQueue queue = new ReferenceQueue();
    
    //只有一个构造方法,必传ReferenceQueue
    PhantomReference<Object> prf = new PhantomReference<>(obj,queue);
    
    //获取的Object永远为空
    prf.get();
    
    //可判断是否已回收
    prf.isEnqueued();
    

5. Handler机制优化

Handler机制中使用软引用或弱引用,避免oom,此处示例弱引用:

private final Thread thread05 = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Message message = new Message();
        message.obj = "子线程处理结果";
        handler05.sendMessage(message);
    }
});

private final Handler handler05 = new MyHandler(new WeakReference<MainAsyncActivityB>(MainAsyncActivityB.this));

//静态内部类
private static class MyHandler extends Handler {
    private WeakReference<MainAsyncActivityB> mActivityWeakReference;

	//构造函数传入
    public MyHandler(WeakReference<MainAsyncActivityB> activityWeakReference) {
        mActivityWeakReference = activityWeakReference;
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        MainAsyncActivityB activity = mActivityWeakReference.get();
        
		//必须判断activity是否为空
        if (activity != null) {
            activity.show_tv.setText(msg.obj.toString());
        }
    }
}
thread05.start();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值