Handler机制

参考文章:

1.https://www.jianshu.com/p/1c79fb5296b6

2.https://www.jianshu.com/p/9e4d1fab0f36

3.https://www.cnblogs.com/cheneasternsun/p/5467115.html

四要点

1.Handler  消息执行者

2.Message  消息

3.MessageQueue  消息列队

4.Looper  消息泵

使用说明:主要是为了线程间通信而设计,常用于子线程发送消息给主线程处理ui消息。

前提说明:

1.由于在主线程的入口,也就是ActivityTherad.main()中,系统已经帮我们把主线程变成looper线程。也就是说在主线中有个looper已开启循环

public static void main(String[] args) {

        ......

        Looper.prepareMainLooper();//为主线程创建Looper,该方法内部又调用 Looper.prepare()

        ......

        Looper.loop();//开启消息轮询

        ......

    }

2.Looper.prepare()说明,该方法主要是给当前本地线程sThreadLocal设置一个looper

public static final void prepare() { 

        if (sThreadLocal.get() != null) { 

            throw new RuntimeException("Only one Looper may be created per thread"); 

        } 

        sThreadLocal.set(new Looper(true)); 

}

3.  Looper.loop()  该方法内开启 死循环,获取当前绑定的MessageQueue,并通过queue.next方法,来获取下一个线程,如果下个线程为空,或者需要延迟,则进入阻塞状态。

public static void loop() {

        final Looper me = myLooper();

        ......

        final MessageQueue queue = me.mQueue;

        ......

        for (;;) {

            Message msg = queue.next(); // might block

            .......

            msg.target.dispatchMessage(msg);

            ......

            msg.recycleUnchecked();

        }

    }

进入Hnadler使用案例

1.在主线程new Handler(), 这一步 主要是关联当前线程的looper,并把关联的loop中的messageQueue作为自己的MQ。

public Handler(Callback callback, boolean async) {

        .....

        mLooper = Looper.myLooper();  // 默认将关联当前线程的looper

        .....

        mQueue = mLooper.mQueue;  //重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上

        mCallback = callback;

        mAsynchronous = async;

    }

2.在工作线程(子线程)中调用Handler.sendMessage(msg),最终会调用下面这行代码

  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

        msg.target = this;    //message中的target关联到当前handler

        if (mAsynchronous) {

            msg.setAsynchronous(true);

        }

        return queue.enqueueMessage(msg, uptimeMillis);  //把消息添加到消息列队

}

3.当Handler.sendMessage(msg)后,主线程中的Looper.loop()方法中的循环,就会抽取出message,然后调用 msg.target.dispatchMessage(msg),让与msg关联的hanlder来分发消息

4.最后来看一下dispatchMessage(msg),该方法中Handler的mCallback一般为空,那么就会执行handleMessage,这里的handleMessage就是我们new Handler()的时候重写的方法,这就完成了整个从子线程发送消息到主线程了。

public class Handler {

  public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

    }

}

注意点

1.一个线程只能由一个looper。因为在创建loop必须调用Looper.prepare(),这一个会获取当前线程然后给他设置一个新的looper()

2.Looper有一个MessageQueue,可以处理来自多个Handler的Message;

3.MessageQueue有一组待处理的Message,这些Message可来自不同的Handler

4.与第三点相同,也就是说,一个线程可以由多个Handler

5.handler.obtainMessage(),是从msg池:sPool中获取一个Message对象,就能避免创建对象,从而减少内存的开销了。

handler造成内存内漏

出现原因:因为handler隐士持有activity引用。(内部内隐士持有外部类引用)

举例:假设一个子线程未运行完毕,这个时候,当前activity已经关闭了,该子线程又持有handler引用,handler又持有ac引用,这就造成了gc无法回收ac,导致内存泄漏

解决方案:

方法一:通过程序逻辑来进行保护。

1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。

2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。

方法二:将Handler声明为静态类。

PS:在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。

静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)。

代码如下:

static class MyHandler extends Handler

    {

        WeakReference mWeakReference;

        public MyHandler(Activity activity)

        {

            mWeakReference=new WeakReference(activity);

        }

        @Override

        public void handleMessage(Message msg)

        {

            final Activity activity=mWeakReference.get();

            if(activity!=null)

            {

                if (msg.what == 1)

                {

                    noteBookAdapter.notifyDataSetChanged();

                }

            }

        }

    }

WeakReference弱引用,与强引用(即我们常说的引用)相对,它的特点是,GC在回收时会忽略掉弱引用,即就算有弱引用指向某对象,但只要该对象没有被强引用指向(实际上多数时候还要求没有软引用,但此处软引用的概念可以忽略),

该对象就会在被GC检查到时回收掉。对于上面的代码,用户在关闭Activity之后,就算后台线程还没结束,但由于仅有一条来自Handler的弱引用指向Activity,所以GC仍然会在检查的时候把Activity回收掉。这样,内存泄露的问题就不会出现了。

你可能感兴趣的:(Handler机制)