美文网首页
Handler知识点汇总

Handler知识点汇总

作者: 效刚 | 来源:发表于2019-02-26 18:08 被阅读0次

    Handler说明:

    Android开发中可以使用Handler发送消息进行线程间的通信。Handler发送并处理与一个线程相关联的Message 和Runnable 【注:Runnable 会被封装进一个 Message,所以它本质上还是一个 Message

    每个 Handler 都会跟一个线程绑定,并与该线程的 MessageQueue 关联在一起,从而实现消息的管理以及线程间通信。

    Handler 的基本用法:

    android.os.Handler handler = new Handler() {

    @Override

            public void handleMessage(final Message msg) {

                // 这里接受并处理消息

            }

    };

    // 发送消息

    handler.sendMessage(message);

    handler.post(runnable);

     Handler 原理解析:

    1.Handler 是如何与线程关联的?

    2.Handler 发出去的消息是谁管理的?

    3.消息又是怎么回到 handleMessage() 方法的?

    4.线程的切换是怎么回事?

    (1)Handler 与 Looper 的关联:

    我们在实例化 Handler 的时候 Handler 会去检查当前线程的 Looper 是否存在,如果不存在则会报异常,也就是说在创建 Handler 之前一定需要先创建 Looper 。

    public Handler(Callback callback,boolean async) {

             //检查当前的线程是否有 Looper

              mLooper= Looper.myLooper();

              if (mLooper== null) {

                    throw new RuntimeException(

                           "Can't create handler inside thread that has not called Looper.prepare()");

                    }

             //Looper 持有一个 MessageQueue

               mQueue= mLooper.mQueue;

     }

    一个完整的 Handler 使用例子:

    class LooperThread extends Thread {

             public HandlermHandler;

             public void run() {

                     Looper.prepare();

                     mHandler = new Handler() { 

                     public void handleMessage(Message msg) {

                              // process incoming messages here

                      }

                  };

           Looper.loop();

         }

     }

    Looper.prepare() :

    //Looper

    private static void prepare(boolean quitAllowed) {

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

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

            }

           sThreadLocal.set(new Looper(quitAllowed));

    }

    Looper 提供了Looper.prepare()方法来创建 Looper ,并且会借助 ThreadLocal 来实现与当前线程的绑定功能。Looper.loop() 则会开始不断尝试从 MessageQueue 中获取 Message , 并分发给对应的 Handler

    也就是说 Handler 跟线程的关联是靠 Looper 来实现的。

    (2)Message 的存储与管理

    Handler 提供了一些列的方法让我们来发送消息,如 send()系列 post()系列 。

    不过不管我们调用什么方法,最终都会走到Message.enqueueMessage(Message,long)方法。

    以sendEmptyMessage(int)方法为例:

    //Handler

      sendEmptyMessage(int)

         ->sendEmptyMessageDelayed(int,int)

            ->sendMessageAtTime(Message,long)

                ->enqueueMessage(MessageQueue,Message,long)

                    -> queue.enqueueMessage(Message,long);

    消息的管理者 MessageQueue负责message消息的存放与管理,MessageQueue 就是个消息队列,负责消息的入队出队。

    (3)Message 的分发与处理

     Looper.loop()  负责对消息的分发

    //Looper

    public static void loop() {

           final Looperme = myLooper();

           if (me == null) {

                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this  thread.");

           }

         final MessageQueuequeue = me.mQueue;

         //...

        for (;;) {

               // 不断从 MessageQueue 获取 消息

               Messagemsg = queue.next();// might block

              //退出 Looper

             if (msg == null) {

                    // No message indicates that the message queue is quitting.

                    return;

             }

            //...

            try {

                   msg.target.dispatchMessage(msg);

                   end= (slowDispatchThresholdMs== 0)? 0 : SystemClock.uptimeMillis();

            }finally {

                 //...

            }

            //...

           //回收 message

            msg.recycleUnchecked();

         }

    }

    loop() 里调用了 MessageQueue.next() ,还调用了 msg.target.dispatchMessage(msg) ,msg.target 就是发送该消息的 Handler,这样就回调到了 Handler 那边去了:

    //Handler

    public void dispatchMessage(Message msg) {

            //msg.callback 是 Runnable ,如果是 post方法则会走这个 if

            if (msg.callback!= null) {

                    handleCallback(msg);

             }else {

            //callback

            if (mCallback!= null) {

                  if (mCallback.handleMessage(msg)) {

                             return;

                  }

            }

           //回调到 Handler 的 handleMessage 方法

              handleMessage(msg);

        }

    }

    dispatchMessage() 方法针对 Runnable 的方法做了特殊处理,如果是 ,则会直接执行Runnable.run()。

    分析:Looper.loop() 是个死循环,会不断调用 MessageQueue.next() 获取 Message ,并调用msg.target.dispatchMessage(msg)回到了 Handler 来分发消息,以此来完成消息的回调。

    注意:loop()方法并不会卡死主线程。

    线程的切换:

    Thread.foo(){

         Looper.loop()

            -> MessageQueue.next()

                -> Message.target.dispatchMessage()

                    -> Handler.handleMessage()

       }

    Handler.handleMessage() 所在的线程最终由调用 Looper.loop() 的线程所决定。

    图示

    (4)小结

    Looper :负责关联线程以及消息的分发在该线程下**从 MessageQueue 获取 Message,分发给 Handler ;

    MessageQueue :是个队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message。

    Handler :负责发送并处理消息,面向开发者,提供 API。

    Handler 发送的消息由 MessageQueue 存储管理,并由 Loopler 负责回调消息到 handleMessage()。

    线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。

    (5)常见的一些问题

    1.Handler 引起的内存泄露原因以及最佳解决方案:

    Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。

    这个泄露是因为 Message 会持有 Handler,而又因为Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

    解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息

    示例代码如下:

    private static class MyHandler extends Handler {

            private WeakReference<HandlerActivity> ref;

            public MyHandler(HandlerActivity activity) {

                 this.ref = new WeakReference(activity);

            }

            @Override

             public void handleMessage(final Message msg) {

                   HandlerActivityactivity = ref.get();

                   if (activity != null) {

                        activity.handleMessage(msg);

                   }

           }

    }

    并且再在Activity.onDestroy()前移除消息

    @Override

    protected void onDestroy() {

             myHandler.removeCallbacksAndMessages(null);

             super.onDestroy();

    }

    注意:单纯的在 onDestroy 移除消息并不保险,因为onDestroy 并不一定执行。

    2.创建 Message 实例的最佳方式

    由于 Handler 极为常用,所以为了节省开销,Android 给 Message 设计了回收机制,所以我们在使用的时候尽量复用 Message ,减少内存消耗。

    方法有二:

    通过 Message 的静态方法Message.obtain();获取;

    通过 Handler 的公有方法handler.obtainMessage();。

    相关文章

      网友评论

          本文标题:Handler知识点汇总

          本文链接:https://www.haomeiwen.com/subject/aitzyqtx.html