Handler如何通过sendMessage(Message msg)方法将新消息加入当前消息队列(一)

首先需要先理清 Handler、MessageQueue、Looper 之间的关系。

我们使用Handler的时候(UI主线程)一般是通过以下两种方法去创建一个Handler实例

1. 最常用的方法:方法1

Handler mHandler =new Handler(){
    @override
    public void handleMessage(Message msg){
        //To Do Something
    }

}


mHandler.sendMessage(msg);//发送消息

去看一下Handler的无参构造方法是怎么创建Handler实例的

/**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive        messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }

无参构造方法里调用了另外一个构造方法,继续看下面的源码

 

/**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

 重点看下面两句

mLooper = Looper.myLooper();

mQueue = mLooper.mQueue;//将Looper的mQueue赋值给mHandler的 mQueue

在Handler的构造方法里面直接通过Looper的myLooper()方法初始化自己的mLooper,我们进入该方法

 

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }


    //下面是Looper中的静态变量 sThreadLocal 的定义
    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 通过myLooper()方法的注释也可以知道,该方法返回的是当前线程的 Looper (注意:一个线程对应唯一的一个Looper)

但是怎么来获取当前的线程呢,进入ThreadLocal的get()方法就知道了

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();//通过这句代码获取到当前的线程
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

 现在我们应该明白了当我们通过方法1创建一个Handler实例的时候,在Handler的构造方法里会为我们获取当前线程的

Looper,并且将该Looper的MessageQueue对象的引用mQueue赋值给Handler的mQueue。所以我们通过Handler的se-

ndMessage()方法发送消息的时候自然也就发送到了该Handler所在线程的Looper所管理的MessageQueue消息队列中。

所以下面这句代码就是发送到了mHandler所在线程(UI线程)的Looper所管理的MessageQueue队列中

mHandler.sendMessage(msg);

 

2. 还有一种使用Handler的方法:方法2

这里我们采用了 IntentService 中的例子

private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
}


@Override
public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
}

重点关注以下代码:

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

在IntentService中自定义了一个Handler  ServiceHandler ,在 new 一个Handler实例的时候,传入了一个参数mServiceLooper

这个Looper是哪里来的呢,代码里是通过HandlerThread的getLooper()方法获取,如果你去看HandlerThread的源码,就会发

现它其实也是通过Looper的myLooper()方法获取到的 HandlerThread 所在线程所对应的那个Looper。

ServiceHandler的构造方法直接调用了父类的构造方法:super(looper),也就是 Handler 的构造方法

接下来我们再去看一下 Handler 的另一个构造函数

/**
     * Use the provided {@link Looper} instead of the default one.
     *
     * @param looper The looper, must not be null.
     */
    public Handler(Looper looper) {
        this(looper, null, false);
    }

可以看到,该构造方法又调用了Handler的另一个构造方法:

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这里依然是和方法1中的构造方法一样的操作,将传入的serviceLooper 最终赋值给了 Handler的mLooper(同时也是子类ServiceHandler的mLooper),再将该Looper对应的 mQueue 赋值给了 Handler 的mQueue(同时也是子类ServiceHandler的mQueue)

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/lollo01/article/details/103814974