美文网首页
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