美文网首页
Handler原理解析

Handler原理解析

作者: Magic11 | 来源:发表于2018-02-02 13:35 被阅读0次

一、Handler简单应用

    为了更直观地分析handler的原理,首先看一个Handler的简单用法,代码如下:

public class MainActivity extends AppCompatActivity {

    private static final int MSG_WHAT = 0x001;
    private static final String HANDLER_KEY = "handler_key";

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

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = mHandler.obtainMessage();
                msg.what = MSG_WHAT;
                Bundle bundle = new Bundle();
                bundle.putString(HANDLER_KEY, "handler message");
                msg.setData(bundle);
                mHandler.sendMessage(msg);
            }
        }).start();
    }

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == MSG_WHAT) {
                Log.i("msg content:", msg.toString());
            }
        }
    };
}

    代码十分简单,首先新创建一个Handler对象,并重写了Handler的 handleMessage 方法,在 onCreate 函数中启动了一个线程,在线程中调用 mHandler 发送一个消息 msg,然后我们会在刚才重写的 handleMessage 方法中接收并处理 msg。整个消息传递的过程看起来十分简单,清晰明了。

二、Handler原理解析

    上面我们看到了Handler使用的一个简单例子,那么Android内部到底是如何实现这种机制的呢,下面将通过分析Handler的源码一步步进行解析。
    首先,看一下Handler的构造函数,Handler的构造函数有很多个,一般我们的调用主要会进入下面这个,

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    这里有两个需要注意的地方,一个是Handler持有Looper对象的引用,那么这个Looper对象的引用指向的是哪呢,我们知道每个线程都有一个Looper,而 Looper.myLooper() 返回的又是当前线程的Looper,当前线程又是哪个呢,因为我们的Hander对象是在主线程,也就是UI线程中创建的,所有Handler持有的正是UI线程的Loopder。而是Hander持有一个消息队列的引用,消息队列对象是从Looper中拿到的,自然也就是UI线程中的消息队列。
    好了,下一步来继续分析Handler发消息的过程,上面例子中的 sendMessage(msg) 方法最后会进入下面的函数

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    下面主要是想将msg放入Handler持有的消息队列中,下面进一步看下 enqueueMessage 方法

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    这里在将msg对象放入消息队列之前,先将它的target变量指向当前Handler对象,注意这一点也是使用Handler容易导致内存泄漏的地方。
    Handler将msg放入消息队列,此时它的发送工作就算完成了,下面的工作要由Looper接手一下,看一下的Looper的 loop 方法

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //死循环
        for (;;) {
            //不断地从消息队列中取消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            //调用Handler的dispatchMessage函数分发消息
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

    loop函数的代码比较多,可以只关注有中文注释的地方,可以看出loop的主要作用是通过一个死循环不断地从消息队列中取出消息,然后通过msg里的target分发消息,这个target前面已经分析过了,就是msg所持有的Handler对象,也就是发送msg的那个Handler,这样处理msg的代码又回到了Handler的代码中。
    下面继续看Handler的 dispatchMessage 函数

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

    到这里已经可以看到 handleMessage 方法了,不过显然 dispatchMessage 里并没有直接调用 handleMessage,这是因为Handler的使用方法不止上面例子中的一种,例如,也可以通过下面的方式调用Handler

mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {

                    }
                }, 1000);

    这种方式会默认创建一个msg对象,并将msg的callback指向Runnable对象,这就对应 dispatchMessage 的第一个分支 if (msg.callback != null)。
    另外,还可以通过如下的方式调用Handler

Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });

    这对应 dispatchMessage 的 else 分支里的 if (mCallback != null),这里还要判断Callback里的handleMessage 是返回 true 还是返回 false, 如果返回false还是会继续进入 Handler里的 handleMessage 方法的。至此,Handler的源码已分析完毕。

三、总结

    通过以上对Handler源码的分析,其实Handler的调用原理,可以用一句话来描述:Handler对象在创建时会持有当前线程的消息队列,Handler在发送消息时,该消息会持有Handler对象,创建Handler那个线程的Looper对象会不断地从消息队列中取出消息,并通过该消息持有的Handler对象分发消息。

相关文章

  • Handler原理解析

    Handler原理解析 Handler的基本创建步骤 要创建Handler首先需要looper对象,looper的...

  • Android中的handler源码解析(超详细)

    Handler是什么? 原理: handler机制中包含4个关键类(下面对源码的解析也是从这4个类入手),Mess...

  • Handler 源码分析

    Handler原理解析 Handler做为Android线程间通信的基础,是开发与面试必备技能。与之相关的有Asy...

  • Handler原理解析

    文章简介:本文通过阅读android源码来搞懂handler运行原理,好了废话不多说,马上开始装逼:几个定义 Lo...

  • Handler原理解析

    一、Handler简单应用     为了更直观地分析handler的原理,首先看一个Handler的简单用法,代码...

  • Handler原理解析

    首先从Handler 的构造方法开始,Handler有几种构造方法,先从最开始的最普通的开始,Handelr ha...

  • Handler原理解析

    Handler可以理解为线程间收发消息的处理器。在Android中最常见的应用场景是子线程使用主线程的Handle...

  • Android Handler机制原理及源码解析

    今天打算写一下Handler机制的原理及源码解析,Handler在我们的开发中用到的频率还是非常高的,同时这也是一...

  • Handler、Looper、MessageQueue源码解析—

    目录 Handler、Looper、MessageQueue源码解析——Handler Handler、Loope...

  • Handler、Looper、MessageQueue源码解析—

    目录 Handler、Looper、MessageQueue源码解析——Handler Handler、Loope...

网友评论

      本文标题:Handler原理解析

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