Android Handler机制

    大家都知道,Android不允许在子线程更新UI,所有的UI操作都在主线程完成,当我们在子线程处理完一些逻辑后需要更新UI怎么做呢,大家都知道可以通过Handler来实现。我们来看一下示例代码:

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {

            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(2000);
                    Message msg = Message.obtain();
                    msg.what = 1;
                    mHandler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    那么为什么在子线程通过调用mHandler.sendMessage(msg)后,就可以在mHandler.handleMessage()里面更新UI了呢,这就是我们今天要搞清楚的问题。
    首先,我们来看一下源码里面对Handler的介绍

/**
 * 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.
 * 
 * <p>There are two main uses for a Handler: (1) to schedule messages and
 * runnables to be executed as some point in the future; and (2) to enqueue
 * an action to be performed on a different thread than your own.
 * 
 * <p>Scheduling messages is accomplished with the
 * {@link #post}, {@link #postAtTime(Runnable, long)},
 * {@link #postDelayed}, {@link #sendEmptyMessage},
 * {@link #sendMessage}, {@link #sendMessageAtTime}, and
 * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
 * you to enqueue Runnable objects to be called by the message queue when
 * they are received; the <em>sendMessage</em> versions allow you to enqueue
 * a {@link Message} object containing a bundle of data that will be
 * processed by the Handler's {@link #handleMessage} method (requiring that
 * you implement a subclass of Handler).
 * 
 * <p>When posting or sending to a Handler, you can either
 * allow the item to be processed as soon as the message queue is ready
 * to do so, or specify a delay before it gets processed or absolute time for
 * it to be processed.  The latter two allow you to implement timeouts,
 * ticks, and other timing-based behavior.
 * 
 * <p>When a
 * process is created for your application, its main thread is dedicated to
 * running a message queue that takes care of managing the top-level
 * application objects (activities, broadcast receivers, etc) and any windows
 * they create.  You can create your own threads, and communicate back with
 * the main application thread through a Handler.  This is done by calling
 * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
 * your new thread.  The given Runnable or Message will then be scheduled
 * in the Handler's message queue and processed when appropriate.
 */

    从上面的注释,我们可以看到,Handler主要有2个作用,1是调度和处理Message,2是在别的Thread去处理Message,还有就是,Handler是跟Thread以及Thread's MessageQueue绑定的。我们先来看看Handler的构造方法(为了阅读方便,对源码做了一些删减,下同)

public Handler(Callback callback, boolean async) {
    mLooper = Looper.myLooper();//1.绑定Looper
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;//2.绑定Looper.mQueue
}

    从Handler的构造方法,我们可以看出,Handler是与Looper以及Looper.mQueue绑定的,而之前源码注释说的是Handler与Thread以及Thread's MessageQueue绑定,那么我们不难想到Looper是与Thread绑定的,那么我们就看看mLooper = Looper.myLooper()的具体实现

public final class Looper {
    /*
     * API Implementation Note:
     *
     * This class contains the code required to set up and manage an event loop
     * based on MessageQueue.  APIs that affect the state of the queue should be
     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
     * idle handlers and sync barriers are defined on the queue whereas preparing the
     * thread, looping, and quitting are defined on the looper.
     */

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

    final MessageQueue mQueue;//2.1在Handler构造方法里面调用的mQueue = Looper.mQueue
    final Thread mThread;
    private Looper(boolean quitAllowed) {//构造方法私有
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    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构造方法的地方
    }
    public static @Nullable Looper myLooper() {
    	return sThreadLocal.get();//1.1在Handler构造方法里面调用的mLooper = Looper.myLooper
    }
}

    我们可以看到,Looper.myLooper()是调用了Looper的static final 成员ThreadLocal<Looper> sThreadLocal里面的get方法,并且Looper的构造方法是私有的,而且构造方法只在Looper.prepare()方法里面有调用,而调用的地方正是构造了一个Looper并且放在了sThreadLocal里面,所以,所有要用到Looper的地方都是通过静态对象sThreadLocal.get()获得的。我们来看看sThreadLocal.get()的实现

public T get() {
        Thread t = Thread.currentThread();//获取当前Thread
        ThreadLocalMap map = getMap(t);//利用currentThread获取ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//利用当前ThreadLocal从Map里获取Entry,Entry的key是ThreadLocal,value是Looper
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    由此我们可以看到,Looper其实是与Thread绑定的,获取到currentThread后又紧接着获取了currentThread.threadLocals,然后从这个Thread.threadLocals(ThreadLocalMap对象)里面去通过ThreadLocal获取Looper,而Handler又是与Looper绑定的,所以最终Handler也是与Thread绑定了,这就验证了Handler注释里面所说的Handler与Thread绑定,那么Handler与Thread's MessageQueue又是如何绑定的呢,其实我们上面贴的Handler的构造方法里面有一行代码mQueue = mLooper.mQueue,我们来看看Looper.mQueue,回到上面Looper的代码,就可以看到mQueue的初始化是在Looper构造方法里面初始化的。
    那么在子线程用主线程创建的Handler去sendMessage为什么这个消息就能到主线程了呢。我们一起来看看代码(代码有精简,方便阅读)

//1
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//2
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
//3
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        return enqueueMessage(queue, msg, uptimeMillis);
    }
//4
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//Message.target = this (Handler与Message绑定)
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//Handler.sendMesage后Message被放进了与Handler绑定的Looper.mQueue中
    }

    消息放进去了,怎么取消息呢,什么时候执行呢,我们来看一下源码里面对Looper的注释

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */
public final class Looper {
}

    子线程创建Handler并使用,需要先调用Looper.prepare()然后再调用Looper.loop(),Looper.prepare()做的工作其实就是创建一个Looper,然后将Looper放进当前线程的ThreadLocalMap里面,我们可以看一下精简过后的代码

//1
private static void prepare(boolean quitAllowed) {
            sThreadLocal.set(new Looper(quitAllowed));
    }
//2
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
//3
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    我们再来看看Looper.loop()的源码

    public static void loop() {
        final Looper me = myLooper();
        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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();

            msg.recycleUnchecked();
        }
    }

    可以看到Looper.loop()里面开了一个for(;;)死循环去不停的轮询消息,取到消息后就调用msg.target.dispatchMessage(msg)里,也就是Handler.dispatchMessage(Meesage msg),我们看一下源码

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//如果构建Message的时候传入了callback,就调用callback.run() callback是一个Runnable
            handleCallback(msg);
        } else {
            if (mCallback != null) {//如果构建Handler的时候传入了一个mCallback,那么就调用callback.handleMessage(msg),返回true表示消息已被处理
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//Handler默认的处理方法
        }
    }

    至此,Handler如何与Looper Thread绑定,消息如何发送,如何分发处理就分析完了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值