Android消息传递机制Handler完全解析之4内存泄漏等问题

Android消息传递机制Handler完全解析之内存泄漏等问题

Android Handler的使用还是要注意几个地方的,比如方法的调用和界面退出了Handler消息还在导致内存泄漏等情况。

top

1、在子线程使用Handler前一定要先为子线程创建Looper,并且让子线程工作

Looper创建的方式是直接调用Looper.prepare()方法,让子线程工作的方法是Looper.loop().
过创建Handler对象时如果没有给它指定Looper,那么它默认会使用当前线程的Looper,而线程默认是没有Looper的,所以使用前一定要先创建Looper。

如果在主线程创建子线程工作的Handler,需要給Handler传入子线程对象HandlerThead。

2、在同一个线程里,Looper.prepare()方法不能被调用两次。因为同一个线程里,最多只能有一个Looper对象。

一个线程里面只能有一个Loooper和一个MessageQueue,如果调用多次创建的方法会抛出异常。
部分源码代码如下:

	//Looper对外暴露的创建Looper方法
    public static void prepare() {
        prepare(true);
    }

	//参数表示是否允许强制退出,一般是允许的
    private static void prepare(boolean quitAllowed) {
		//sThreadLocal.get()返回的是跟Looper绑定的对象,如果该对象已经创建,不能再调用prepare方法,否则会抛出异常。
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
		//第一次调用prepare,就会创建Looper,并且把Looper跟ThreadLocal绑定
        sThreadLocal.set(new Looper(quitAllowed));
    }

	//这里是私有方法,只能自身调用
	//MessageQueue就是这里实例化的
	//一些耗时处理都是在Thread中实现的
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//创建MessageQueue
        mThread = Thread.currentThread();
    }

3、只有调用了Looper.loop()方法,Handler机制才能正常工作。

Looper负责管理MessageQueue,它的loop()方法负责从MessageQueue里取出消息并交给Handler处理,
所以如果没有调用Looper.loop()方法,消息就不会被取出和处理。

主线程Looper.loop()方法是Activity创建的时候调用了的,不要我们管,子线程是要我们自己调用的。

调用两次loop方法会怎么样?

源码里面没有报异常,但是loop方法里面有取消息的循环,但是如果多次调用,里面会有多个取消息的循环,是同一个MessageQueu里面取消息,所以多个循环也是没用的,最后还是按顺序一个一个取。

4、Looper.loop()方法一定要在调用了Looper.prepare()方法之后调用。

那是因为如果当前线程还没有Looper,是不能调用Looper.loop()方法开启消息轮询的,否则会报错。

部分源码如下:

    /**
     * Looper的核心方法
     */
    public static void loop() {
        final Looper me = myLooper();
		//要先调用Looper.prepare(),否则会报错,因为Looper没有实例化
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
		...
	}

5、不要在主线程调用Looper.prepare()方法。

这是因为在Android系统创建主线程的时候就已经调用了Looper.prepare()方法和Looper.loop()方法,
这也是为什么我们在主线程使用Handler时不需要调用这两个方法的原因。

6、当我们在子线程使用Handler时,如果Handler不再需要发送和处理消息,那么一定要退出子线程的消息轮询。

如果页面退出,也记得把Handler的消息清空,比如在Activity 退出的回调方法onDestroy中对消息进行清除。
Handler.removeCallbacksAndMessages(null);

7、使用Message.obtain()来获取Message消息对象。

避免过多创建对象。

8、如果在Activity界面接收消息,一般使用弱引用,避免消息在Activity销毁后还在收发消息,造成内存泄漏。


/** 
     * 声明一个静态的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();
			// 判断Activity没被销毁才继续....  
            if (activity != null){  
                
  
            }  
        }  
    }

共勉:往前走

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值