Android Handler 消息机制

目录

 

一、Handler的简单使用

二、ThreadLocal 工作原理

三、Looper类

四、Handler 类

五、MessageQueue类

 流程

相关问题


一、Handler的简单使用

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();
        }
    }

二、ThreadLocal 工作原理

Handler创建时会采用当前线程的Looper来构造消息循环,ThreadLocal可以在不同线程中互不干扰地存储并提供数据,通过ThreadLocal 可以轻松获得每个线程的Looper。ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,而且只能在指定线程获取数据,其他线程无法获取到数据。不同线程访问同一个ThreadLocal 的get方法时,ThreadLocal 内部会从各自的线程中取出一个数组,然后从数组中根据当前ThreadLocal的索引去查找对应的值,不同线程的数组是不同的,所以不同线程间数据互不干扰。

ThreadLocal是一个泛型类,定义为 public class ThreadLocal<T>,它的set方法:

public void set(T value){
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}

 在上面的set方法中,首先通过getMap方法来获取当前线程的ThreadLocalMap,在Thread类内部有一个成员专门用于存储线程的ThreadLocal数据:ThreadLocalMap threadLocals,如果threadLocals的值为null,那么就需要进行初始化,然后再将值存储。ThreadLocalMap是ThreadLocal的内部类,在内部有一个Entry数组(Entry是ThreadLocalMap的内部类),ThreadLocal的值就存在这个数组中。接下来看下get方法。

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);     //拿到当前线程的ThreadLocalMap
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);    // 以该ThreadLocal对象为key取value
        if (e != null)
            return (T)e.value;
    }
    return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

相关文章:【ThreadLocal】深入JDK源码之ThreadLocal类

ThreadLocal源码分析

 

三、Looper类

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.

该类包含设置和管理基于MessageQueue的事件循环所需的代码。影响队列状态的api应该在MessageQueue或Handler上定义,而不是在Looper本身上定义。例如,在队列上定义空闲处理程序和同步屏障,而在looper上定义线程准备、循环和退出。

成员变量:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;
    private long mTraceTag;

    /* If set, the looper will show a warning log if a message dispatch takes longer than time. */
    private long mSlowDispatchThresholdMs;

其中sThreadLocal 保存各个线程的Looper。Looper通过prepare()方法创建。

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

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

//创建主线程Looper,Android中会主动调用此方法,所以 UI 线程默认有Looper
public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

在app启动时会在AcitvityThread的main方法中调用prepareMainLooper()方法完成主线程Looper初始化。

类中还有一系列get方法来返回线程的消息队列,Looper,mainLooper,线程等。以及退出方法。

//当不再处理消息队列消息时退出。退出后再往队列添加信息会返回false

//此方法是不安全的,在退出时可能还有信息没有发送
public void quit() {
        mQueue.quit(false);
    }


//在退出前处理完队列中消息,但是挂起延迟消息不会被处理
public void quitSafely() {
        mQueue.quit(true);
    }

 接下来是最重要的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;

        // 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();

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

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // 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.recycleUnchecked();
        }
    }

首先获取线程的消息队列和Looper,进行一些初始化后进行for死循环,调用queue.next()获取队列中消息,当没有消息时阻塞,如果有消息时则处理,即msg.target.dispatchMessage(msg)。 msg.target是发送这条消息的Handler对象,在放入队列时设置,这样消息就分发给dispatchMessage方法处理,此方法是在创建Handler对象所在线程执行,这样就完成了线程切换。注意到当消息为null时退出loop方法,而当Looper的quit方法被调用时,Looper就会调用消息队列的quit()或者quitSafely方法来退出队列,当队列被标记为退出状态时,它的next方法就会返回null。

 

四、Handler 类

Handler是用来发送和处理{@link Message},Runnable和线程的{@link MessageQueue}关联的对象。每个Handler实例与单个线程和该线程的消息队列相关联。当您创建一个新的Handler时,它被绑定到创建它的线程和创建它的线程的消息队列——从那时起,它会将消息和Runnable发送到该消息队列,在它们从消息队列发出时执行它们。

用途:调度消息和将来某个时候执行的Runnable;入队,要在不同于您自己的线程上执行;

其成员变量:

// 实例化Handler时可以使用回调接口,以避免必须实现自己的Handler子类(即重写handleMessage方法)
public interface Callback {
        public boolean handleMessage(Message msg);
    }

    final Looper mLooper;
    final MessageQueue mQueue; // 消息队列
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;

构造方法,有多个重载:

public Handler() {
        this(null, false);
    }

public Handler(Callback callback) {
        this(callback, false);
    }

public Handler(Looper looper) {
        this(looper, null, false);
    }

public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
public Handler(boolean async) {
        this(null, async);
    }

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;
    }

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

接下来看一下Handler传递消息相关方法:

 public final boolean post(Runnable r){
     return sendMessageDelayed(getPostMessage(r), 0);
 }

 public final boolean sendMessage(Message msg){
     return sendMessageDelayed(msg, 0);
 }

 public final boolean postAtTime(Runnable r, long uptimeMillis){
     return sendMessageAtTime(getPostMessage(r), uptimeMillis);
 }
 
 public final boolean sendEmptyMessage(int what){
     return sendEmptyMessageDelayed(what, 0);
 }

 public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
     return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
 }
 
 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
 }
 
 public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
  }

 public final boolean postDelayed(Runnable r, long delayMillis){
     return sendMessageDelayed(getPostMessage(r), delayMillis);
 }

 public final boolean postDelayed(Runnable r, Object token, long delayMillis){
     return sendMessageDelayed(getPostMessage(r, token), delayMillis);
 }

 public final boolean postAtFrontOfQueue(Runnable r){
     return sendMessageAtFrontOfQueue(getPostMessage(r));
 }
 
 public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
 }
 ....

 传递消息类型有两种,一种是Runnable,一种是 Message,传递方式有延迟发送,按时发送。也可发送空Message,也可以将消息放到队列前面。可以看到最终发送调用sendMessageDelayed,sendMessageAtTime方法,消息放到队列调用enqueueMessage方法:

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);
    }

 无论哪种方式,最终调用enqueueMessage方法,其中设置消息的target为当前Handler,并调用当前Handler所属线程消息队列的 enqueueMessage 方法。

 接下来看下处理消息的方法:

public void dispatchMessage(Message msg) {
        // 是否传递 runnable
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            // 是否设置Callback(如果没有则实现了子类)
            if (mCallback != null) {
                // Callback的handleMessage方法在初始化Handler时传入的Callback中实现
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

// 执行传递过来runnable
private static void handleCallback(Message message) {
        message.callback.run();
}

// 由子类重写
public void handleMessage(Message msg) {
}
 

handleCallback处理Runnable类型消息,在其中执行其run方法,CallBack及Handler的handleMessage方法均由用户实现。

 

五、MessageQueue

    MessageQueue用来存储传递的消息,重点关注enqueueMessage和next方法,enqueueMessage:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 第一个消息,如果队列阻塞则唤醒
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 判断是否需要唤醒队列(目前阻塞及消息是队列中最早的异步消息则唤醒)
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 将消息插入队列
                for (;;) {
                    prev = p;
                    p = p.next;
                    // 当前位置为空或者当前消息when比待插入when大跳出循环
                    if (p == null || when < p.when) {
                        break;
                    }
                    // 如果当前消息为异步消息则无需唤醒
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 找到位置并插入
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

 根据传递消息设置的when找到位置并插入队列(详情看注释)。next方法:

 

 Message next() {
        // 如果消息循环已经退出并已被释放,则返回此处。
        // Looper的loop方法会结束
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        // 不停地检测队列是否有符合出队的消息
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // 查找队列中的下一个异步消息。(设置屏障)
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                       //下一条消息还没有准备好。设置一个超时,在它准备好时唤醒它。
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 获得一个消息 出队
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 没有更多消息
                    nextPollTimeoutMillis = -1;
                }

                // 现在所有挂起的消息都已处理完毕,处理quit消息
                if (mQuitting) {
                    dispose();
                    return null;
                }

                //如果第一次空闲,则获得要运行的空闲组的数量。
                //mIdleHandlers仅在队列为空或队列中的第一个消息(可能是一个障碍)将在将来处理时                
                //运行。
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // 没有idle handlers 需要执行.  循环并等待消息.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // 执行 idle handlers.
            //我们只在第一次迭代中到达这个代码块.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // 释放对handler的引用

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // 将空闲处理程序计数重置为0,以便不再运行它们.
            pendingIdleHandlerCount = 0;

            // 在调用空闲处理程序时,可能已经传递了一条新消息
            //因此,请返回并再次查找未等待的消息。
            nextPollTimeoutMillis = 0;
        }
    }

 循环检测队列中是否有消息需要出队,有则返回。

 流程

  通过Handler传递消息,设置其target对象为发送的Handler,然后放入同线程的MessageQueue中,线程中的Looper会一直将MessageQueue的消息取出并调用其target对象(即发送消息的Handler)的dispatchMessage方法分发并处理,Looper运行在创建时的线程,这样就完成了线程切换。(下图来源于网络)

相关问题

1.内存泄漏

 java 匿名内部类和非静态内部类会自动隐式持有当前类的外部引用,所以当使用匿名内部类初始化Handler时,持有activity/Fragment 引用,当activity/fragment 退出 但还有消息未处理时,会造成内存泄漏(主线程的Looper对象会伴随该应用程序的整个生命周期。当在主线程中初始化Handler时,该Handler就会自动和主线程Looper的消息队列关联起来。所有发送到消息队列的消息Message都会拥有一个对Handler的引用)

解决方法可在退出前清空消息队列,调用Handler方法removeCallbacksAndMessages(null)或者采取静态内部类,并持有外部类弱引用 方式。

2.Looper.loop()中死循环为什么不会造成应用卡死?网上说法如下:

 在MessageQueue的next方法,在for循环中,会调用nativePollOnce方法,如果消息队列中没有消息存在nativePollOnce就不会返回,阻塞队列。在MessageQueue的方法中将消息插入队nativePollOnce列后,如果状态位needWake为true则调用nativeWake方法,在此方法中触发上面提到的nativePollOnce方法返回。nativePollOnce方法和nativeWake方法都是本地方法,源码在native层。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值