Android Handler正确使用姿势

以前项目中会遇到的内存泄漏的问题,其中就有Handler使用姿势不正确造成的。修改过后没有总结写篇博客记录,前几天看书看到这里,顺便写篇博客记录一下。

容易造成内存泄漏的一种Handler使用方法:将Handler声明为Activity的内部类。在Java语言中,非静态内部类会持有外部类的一个隐试引用,这样就可能造成外部类无法被垃圾回收。而导致内存泄漏。

private final Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // ...
        }
    };

那么正确的使用就是:

1.将Handler声明为静态内部类。并持有外部类的若引用。

2.在子线程中使用Handler,这是需要我们自己创建一个Looper对象。

下面代码介绍一下第一种用法:

/**
 *  正确使用Handler方式
 */
public class HandlerActivity extends AppCompatActivity {
    

    private final MyHandler mHandler = new MyHandler(this);

    /**
     * 静态的匿名内部类不会持有外部类的引用
     */
    private static final Runnable sRunnable = new Runnable() {
        @Override
        public void run() {
            // ...你的操作

        }
    };


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

        mHandler.post(sRunnable);
    }


    /**
     * 声明一个静态的Handler内部类,并持有外部类的弱引用
     */
    private static class MyHandler extends Handler{

        private final WeakReference<HandlerActivity> mActivty;

        private MyHandler(HandlerActivity mActivty) {
            this.mActivty = new WeakReference<HandlerActivity>(mActivty);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            HandlerActivity activity = mActivty.get();
            if (activity != null){
                // ....

            }
        }
    }

}

上面在Activity使用就需要声明一个内部类,下面再看一个,将自定义Handler抽出去,也同样达到效果的小栗子:

1.首先创建一个类,通过泛型将实例传入

public class UIHandler<T> extends Handler {

    protected WeakReference<T> ref;

    public UIHandler(T cls){
        ref = new WeakReference<T>(cls);
    }

    public T getRef(){
        return ref != null ? ref.get() : null;
    }
}

2.看下activity中使用,直接用myHandler对象发送message即可。

private static class UIMyHandler extends UIHandler<HandlerActivity>{

        public UIMyHandler(HandlerActivity cls) {
            super(cls);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            HandlerActivity activity = ref.get();
            if (activity != null){
                if (activity.isFinishing())
                    return;

                switch (msg.what){

                    case 1:{

                        break;
                    }

                    // ...

                }

            }
        }
    }

    private UIMyHandler myHandler = new UIMyHandler(this);

最后在简单介绍一下,Java弱引用以及软引用还有虚引用。

个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。若果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
          和弱引用功能类似的是WeakHashMap,他对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效的一处。WeakHashMap使用ReferenceQueue实现的这种机制。
          java.lang.ref包中提供了几个类:SoftReference类—>软引用;
                                                              WeakReference类—>弱引用;
                                                              PhantomReference—>虚引用;(相当于没有持有引用,形同虚设,随时可能被回收)
          弱引用实践场景:自己定义Handler类采用弱引用方式,防止内存泄漏。
          软引用场景:应用中肯定会有很多的默认的图片资源,会多次用到。如果每次都去获取,读取文件需要硬件操作,速度慢,导致性能降低。所以考虑将图片缓存起来,需要时直接从内存中获取,但是图片占用内存空间很大,容易OutOfMemory。这时考虑软引用。 




  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值