Handler机制

Handler是Android开发必须使用到的技术,使用呢也很简单,在主线程重写Handler的handleMessage方法,在子线程中通过handler的sendMessage()方法发送消息。


Handler

通过这张图可以很好的理解Handler机制,其中有几个角色ActivityThread、Handler、Message、MessageQuene、Looper,首先对这些角色做一下简单介绍:

ActivityThread:程序的启动入口,这个类也就是我们平常所说的主线程(UI线程),更新UI的操作必须在主线程中进行

Handler:字面意思就是操控者,在子线程中要通过handler的sendMessage()方法发送消息到MessageQuene中,并且通过重写Handler的handleMessage()方法处理消息。在Handler中持有MessageQuene和Looper的对象
MessageQuene:消息队列,就是存放Message的一个队列,对handler发送过来的消息进行插入,Looper从这个队列中循环取出消息
Message:也就是消息,在Message中定义了几个字段分别表示不同的信息。

ActivityThread.main()

public static void main(String[] args) {
        //......
        //只贴出相关代码
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();
        //.....
    }

main()方法就是程序的入口,通过查看ActivityThread的main()方法,可以发现这里调用了Lopper类的prepareMainLooper()方法和loop()方法,接下来在看Looper类

Looper

static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper;  // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;

在Looper中包含了这几个字段

ThreadLocal:每个线程中都有一个ThreadLocal,这里用来保存当前线程的Looper对象
MessageQuene:消息队列
Thread:当前的线程对象
接下来在看prepareMainLooper()和loop()方法

public static void prepareMainLooper() {
        prepare(false);//这里调用了prepare方法
        synchronized (Looper.class) {
            if (sMainLooper != null) {//这里判断sMainLooper 是否为空
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();//为空则调用myLooper()方法从ThreadLocal中取出Looper对象
        }
    }


private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
            //可以发现,prepare方法只能调用一次,也就是一个线程中只能有一个Looper,否则就会抛出异常
        }
        sThreadLocal.set(new Looper(quitAllowed));//ThreadLocal中如果没有Looper对象,则new一个
    }

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//取出Looper对象
    }
public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        for (;;) {
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

    //下面是loopOnce中的方法
    //从mQuene中循环取出消息(mQuene就是上面所说的MessageQuene这个字段)
    Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }
    //通过Message的target分发消息(就是发送这条消息的Handler)
    msg.target.dispatchMessage(msg);
    //这里清空msg里面的表示、参数等清空
    msg.recycleUnchecked();

通过上面的分析我们发现,loop方法中会取出内部的消息序列器,并且迭代消息,根据msg的target属性进行分发操作,但是现在有一个问题,MessageQuene中的消息是从哪里来的?这个时候就到了我们的Handler了。

Handler

首先还是先看Handler的字段

    final Looper mLooper;//通过Looper传递MessageQuene
    final MessageQueue mQueue;//在Handler中并没有实例化,而是指向了Looper的MessageQuene
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;

接下来在看Handler的构造函数

public Handler(@Nullable Callback callback, boolean async) {
        //.............
        mLooper = Looper.myLooper();//从当前线程的ThreadLocal中取出Looper对象
        if (mLooper == null) {
        /*
        *注意:如果是在主线程中的话,系统默认已经调用了Looper.prepare()方法,但是在子线程中创建
        *时我们要手动调用prepare()方法,否则就会抛出如下异常,也可以在创建Handler对象时传入当前
        *线程的Looper对象
        */
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//指向Looper的MessageQuene
        mCallback = callback;
        mAsynchronous = async;
    }

接下来在看Handler是如何发送消息的,其实不论我们调用sendMessage()还是其他方法最终都会走到sendMessageAtTime()方法中

public boolean sendMessageAtTime(@NonNull 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);
    }

sendMessageAtTime()方法接收两个参数,一个Message对象,和一个时间参数,表示发送消息的时间(这个值为系统当前的时间+延时时间,比如调用sendMessageDelayed方法时),然后将这两个参数都传入了enqueueMessage方法中,在进入这个方法看一下

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        //将msg的Target属性指定为this,也就是当前Handler,也就对应了Looper中的loop方法
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
        //通过MessageQuene将msg进行入队操作,到这里就知道MessageQuene中的消息是从哪里来的了
    }

总结:

  • 一个线程中只能存在一个Looper对象,但是可以有多个Handler
  • 一个Looper可以绑定多个Handler,反之一个Handler只能绑定一个Looper(也就是当前线程的Looper)

创建Handler之后,通过Handler发送Message,在Handler内部将Message存储到MessageQuene中,然后通过Looper从MessageQuene中循环取出Message,然后在通过Handler的handleMessage()方法处理Message,就可以完成UI的更新
个人理解哦!!!!

你可能感兴趣的:(Handler机制)