Android 中 Handler,Looper,HandlerThread 的关系分析

Android 中 Handler,Looper,HandlerThread 的关系分析

最近项目中要用到 HandlerThread,对其的用法一直不甚了解,趁着五一放假就花了点时间研究一下,顺便备份在博客上。

因为刚开始研究的是 HandlerThread,所以我们就从 HandlerThread 入手,我们先来看一下它的源代码

/*
 * Copyright (C) 2006 The Android Open Source Project
 */

package android.os;

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
    int mPriority;//线程优先级
    int mTid = -1;//TID
    Looper mLooper;//Looper成员变量

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;//构造函数,设置默认线程优先级
    }
    
    /**
     * Constructs a HandlerThread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;//构造函数,根据参数设置线程优先级
    }
    
    /**
     * Call back method that can be explicitly over ridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {//主要提供给子类,让子类去重写
    }

    public void run() {//run方法,终点来了
        mTid = Process.myTid();//获取TID
        Looper.prepare();//后面在Looper类里看
        synchronized (this) {//同步
            mLooper = Looper.myLooper();//后面在Looper类里看
            notifyAll();//唤醒持有该对象的并且wait的线程
        }
        Process.setThreadPriority(mPriority);//设置线程优先级
        onLooperPrepared();//HandlerThread类里没有实现,子类可以实现,做一些预处理操作
        Looper.loop();//后面在Looper类里看
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {//如果线程死掉了,返回null
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {//如果线程活着,但是为null,就一直等待,与run方法里面的synchronized相一致
                try {
                    wait();//当线程没有被start(start之后才会alive)或者没有获取到Looper对象时wait。注意run方法中有notify操作。
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;//返回Looper成员变量
    }
    
    /**
     * Ask the currently running looper to quit.  If the thread has not
     * been started or has finished (that is if {@link #getLooper} returns
     * null), then false is returned.  Otherwise the looper is asked to
     * quit and true is returned.
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();//后面在Looper类里看
            return true;
        }
        return false;
    }
    
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {//返回TID
        return mTid;
    }
}

源代码不是很多,有些涉及到Looper类里面的方法,我们再来看一下Looper类的源代码(只分析涉及到的方法和成员变量)。

/*
 * Copyright (C) 2006 The Android Open Source Project
 */

package android.os;

import android.util.Log;
import android.util.Printer;
import android.util.PrefixPrinter;

public class Looper {
    private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    final MessageQueue mQueue;
    final Thread mThread;
    volatile boolean mRun;

    private Printer mLogging = null;
    private static Looper mMainLooper = null;  // guarded by Looper.class

     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());//把和当前线程相关的Looer变量(参考Looper构造方法)放进sThreadLocal中
    }

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        Looper me = myLooper();//获取和当前线程相关的Looper变量
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        MessageQueue queue = me.mQueue;//和当前线程相关的Looper变量的MessageQueue
        
        // 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();
        
        while (true) {//死循环哟,不过没关系,在MessageQueue中有处理,涉及到wait和notify,可以去MessageQueue中探究。
            Message msg = queue.next(); // might block,获取Message
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }

                long wallStart = 0;
                long threadStart = 0;

                // 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);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }

                msg.target.dispatchMessage(msg);//这一句最关键,Message的Target是什么?没错,是Handler,下面我们就来看一下Handler类

                if (logging != null) {
                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    if (logging instanceof Profiler) {
                        ((Profiler) logging).profile(msg, wallStart, wallTime,
                                threadStart, threadTime);
                    }
                }

                // 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.recycle();//回收利用Message,所以以后我们使用Message的时候,多使用obtain方法。
            }
        }
    }

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }
    
    /**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
    public static MessageQueue myQueue() {
        return myLooper().mQueue;
    }

    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

    public void quit() {
        Message msg = Message.obtain();
        // NOTE: By enqueueing directly into the message queue, the
        // message is left with a null target.  This is how we know it is
        // a quit message.
        mQueue.enqueueMessage(msg, 0);
    }
}

我们来看一下Handler类的源代码

/*
 * Copyright (C) 2006 The Android Open Source Project
 */

package android.os;

import android.util.Log;
import android.util.Printer;

import java.lang.reflect.Modifier;

/**
 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread 
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * /
public class Handler {

    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";

    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {//重要,在Lopper.loop()方法里面里调用的就是这个方法
        if (msg.callback != null) {
            handleCallback(msg);//msg的callBack成员变量是Runnable类型,这里执行的是msg.callback.run(),但是我们一般不给Message的callback成员变量赋值。
        } else {
            if (mCallback != null) {//如果我们给new()的Handler类的Callback类型的成员变量赋值,就往下面执行,但是我们一般不这么做。
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//我们一般在这做我们想要的操作,这个方法需要我们继承Handler类后重写。
        }
    }

    /**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn't one, this handler won't be able to receive messages.
     */
    public Handler() {
        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 = null;
    }

    /**
     * Constructor associates this handler with the queue for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     */
    public Handler(Callback callback) {
        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;
    }
    public final Message obtainMessage()
    {
        return Message.obtain(this);//获取msg,最后调用的msg的obtain()方法,最后msg的target就是this,也就是调用者Handler
    }
     /**
     * Use the provided queue instead of the default one.
     */
    public Handler(Looper looper) {//MessageQueue怎么关联起来,其实就是在这里关联起来的,通过Handler的构造方法。
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
    }

    /**
     * Use the provided queue instead of the default one and take a callback
     * interface in which to handle messages.
     */
    public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
    }

    // if we can get rid of this method, the handler need not remember its loop
    // we could instead export a getMessageQueue() method... 
    public final Looper getLooper() {
        return mLooper;
    }


    private final void handleCallback(Message message) {
        message.callback.run();
    }

    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    IMessenger mMessenger;
}

Looper类和Handler类的源代码不完整,只是分析了和HandlerThread相关的成员变量和方法。

经过我们的一步步分析,现在思路就清晰了:

1. 当HandlerThread运行到Looper.loop()的时候,一直死循环。通过msg.target.dispatchMessage(msg)方法让msg的target(当通过Handler的obtainMessage()系列方法获取msg的时候,msg的target就是该handler)也就是Handler去通过它的handleMessage(msg)方法去处理msg。

2. 但是msg是那里来的?通过看源代码我们发现是通过当前线程的Looper的MessageQueue类型的变量mQueue.next()方法得到的。

3. Handler也有一个MessageQueue类型的变量,那么,Handler的MessageQueue变量怎么和Looper类的MessageQueue类型变量有关系吗?

4. 记不记得Handler类有一个构造方法叫public Handler(Looper) ? 对了,就是这个构造方法让他们产生了关系。( HandlerThread有一个Looper类型的变量,通过getLooper()方法能获取,传入到Handler类的构造方法,这样,Handler就和HandlerThread联系起来了)。

5. 以至于最后HandlerThread操作的是和Handler同一个MessageQueue。

6. Handler可以通过sendMessage(msg)系列方法把msg放到MessageQueue,然后HandlerThread把msg从MessageQueue里面取出来,然后调用Handler的handleMessage(msg)方法处理。

通俗的总结一下运行时的流程:Handler把Message放到MessageQueue,HandlerThread不停的从MessageQueue里拿出来Message,然后调用Handler的HandleMessage(Message)方法不停的处理Message。

经过分析,我们来写一个demo测试一下,有消息队列的线程(非主线程):

工程如下

HandlerThread分析Demo

下面是我测试结果:


结果表示:HandlerThread确实维护了一个消息队列,从Log中可以看出他们的TID都是一样的。

总结:

1. HandlerThread维护了一个消息队列,这样我们不用到处新建对象。

2. Message其实有一套缓冲+循环利用机制,以后用到Message的地方都用obtain()系列方法获取,能节约资源,提高效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值