Hanlder、Looper、MessageQueue源码解析

Handler介绍

Handler是Android提供给我们用来更新UI的一套机制,也是一套消息处理机制。在Android的源码中有很多地方可以看到它的身影,最熟悉就是Activiy生命周期的回调方法,就是通过这套机制实现的。Handler的出现就是为了保证UI线程的安全,因为Android不允许在非UI线程中更新UI组件,所以所有通过非UI线程得到的数据,都需要通过这套机制来进行数据更新。当然了一个Handler还不足以实现这么强大功能,它还需要结合Looper、MessageQueue和Message以及当前线程来实现了一个消息循环机制。

下面就来介绍下它的几个兄弟:
Looper:循环器,循环不断地管理MessageQueue接收和分发Message或Runnable的工作。每一个线程最多只会有一个Looper对象
MessageQueue:消息队列,存放Message或Runnable对象的地方。每一个线程最多只会有一个MessageQueue对象
Message:消息体,主要功能是对消息进行封装

工作流程
一般情况下,我们是在非UI线程中执行一些耗时的操作后,把一些数据封装到Message消息体中,通过在主线程创建的Handler对象,把消息放入MessageQueue中,当Looper对象发现MessageQueue中有Message,就开始循环消息队列,Looper拿出消息后把消息发送给Handler,由dispatchMessage回调到我们自己实现的handleMessage方法中。

源码分析

1、Looper

Looper的源码并不复杂,一共298行,有用代码不过150行,而对于消息循环我们只需要关注prepare()和loop()两个方法即可。
先看prepare():

public static void prepare() {
        prepare(true);
    }
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));
    }

调用prepare()方法后,又调用了prepare(true);这个形参的意义是是否可以退出消息循环,一般在非UI线程都是可以退出的,但是在UI线程是不允许退出的。那么问题来了,为什么UI线程要不允许消息循环退出呢?这个问题稍后再做解释。在prepare(true)方法中首先判断了sThreadLocal.get()是否为空,那这个sThreadLocal是什么呢?简单的说就是一个存储类为所有线程所共享,但为每个线程提供独立的变量副本,即每个线程都可以独立的修改自己的变量,而不会影响其他线程所对应变量的值。
不为空时会抛异常即一个线程只允许创建一个Looper、
为空时就会把创建的Looper实例保存到ThreadLocal中。
再看Looper的构造:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

在Looper的构造中又创建了一个消息队列,因Looper对象在每个线程中只能创建一个,所以MessageQueue也只能创建一个对象。

然后看下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;
        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;
            }
            ....省略....
            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ....省略....
            //消息对象进行回收
            msg.recycleUnchecked();
        }
    }

第2行获取Looper对象,为空则抛出异常,异常提示为没有Looper对象,prepare()方法没有在当前线程调用,所以这两个方法调用是有顺序的,必须调用prepare()然后再调loop()方法
第6行获取消息队列对象
第11行从消息队列中取消息,如果没有消息就会阻塞,也就是代码执行到这就先停止,调度器将忽略该线程,不会分配给线程任何CPU时间。会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生才会唤醒主线程工作
第22行msg.target就是往消息队列发送消息的Handler,当拿到消息队列中的消息后,就会把消息发送到Handler的dispatchMessage()方法内

Looper主要作用:

保证一个线程只有一个Looper对象和一个与之对应的MessageQueue对象
不断从消息队列中取消息,并把消息交给与之关联的Hanlder对象的dispatchMessage方法去处理,并对消息对象进行回收

2、Handler

使用Handler一般我们是在UI线程创建一个对象并重写handleMessage()方法,根据msg.what来做相应的处理,代码如下

private static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                   break;
                default:
                    break;
            }
        }
    };

来看下源码:

public Handler() {
        this(null, false);
    }
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;
    }

第11行拿到当前线程的Looper对象
第16行拿到当前线程的MessageQueue对象

然后再看下发送消息的方法sendMessage()

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
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);
    }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

这里msg.target=this 就是把当前的Handler对象赋值给了msg.target
再看下enqueueMessage()方法:

boolean enqueueMessage(Message msg, long when) {
        .....省略.....

        synchronized (this) {
            .....省略.....
            // We can assume mPtr != 0 because mQuitting is false.
            //唤醒主线程
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

通过enqueueMessage()方法中的第8行代码唤醒主线程,使阻塞的线程进入就绪状态,准备继续循环消息队列。
当有消息时会调用dispatchMessage()方法,再看下源码:

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

在上一篇文章已经介绍过,当使用Handler.post()发送消息时,走第3行代码,当使用有参Callback构造对象时走。
第6行代码,当使用无参构造函数构造Handler对象时走第10行代码
最后就调用到了我们写的handleMessage()方法中来更新UI了

Handler主要作用
1. Handler构造方法,会首先得到当前线程的Looper对象和与之对应的MessageQueue
2. 通过Handler的sendMessage()方法发送消息,并把消息放入到MessageQueue
3. 唤醒消息循环后,通过Handler的dispatchMessage()方法把消息发送到UI线程,实现UI的更新

其它

那我们通常在UI线程创建Hanlder对象时,并没有调用Looper中的parpare()和loop()方法,这就要说Android应用的入口了,以前一直以为是入口是Activity的onCreate()方法,其实应该是ActivityThread和普通的java类一样,入口也是一个main()方法。来看下源码:

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

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

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

可以看到第21行和第37行帮我们调用了prepareMainLooper和loop两个方法。
prepareMainLooper方法帮我们构建了主线程中的MessageQueue和Looper对象
loop方法开始了消息循环
所以我们在开发过程中不需要写。
再看下prepareMainLooper源码:

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

还记得在讲Looper.prepare()源码时那个问题吗?为什么UI线程要不允许消息循环退出呢?因为在prepareMainLooper这个方法中,源码给我们传了false。因为ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的程序也就可以退出了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值