Handler源码解析

  • Post author:
  • Post category:其他




Handler 源码解析



Handler

子线程与主线程之间的沟通中介,用于传递消息。



基本使用



创建 Handler 对象,重写 handlerMessage 方法
Handler handler = new Handler(Looper.getMainLooper()){
    @Override
    public void handleMessage(@NonNull Message msg) {
       // 处理消息
      
    }
};



发送消息
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);



源码解析

Handler 的运行依赖 MessageQueue、Looper,MessageQueue 是消息队列,用于存放 Handler 发送的消息,Looper 会无限循环查找消息队列中的消息,有消息就取出,没有就等待。



Looper

对消息队列(MessageQueue)进行循环,获取消息(Message)给 Handler 处理。

Looper 通过 prepare 创建 Looper 对象,每个线程只允许创建一个 Looper 对象,并将创建的对象保存在 sThreadLocal 中。在主线程中创建 Handler 时,不需要自己创建 Looper,系统运行时就帮我们创建了 Looper .

public final class Looper {
  
  	...
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    final MessageQueue mQueue;
    final Thread mThread;
  
  	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));
    }
  
  	
    // 由 Android 环境创建,在 ActivityThread 中的 main 方法
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
  
  	public static void loop() {
        ...
        for (;;) {
          	// 循环从消息队列中取消息
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }
  
  	private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // 取到消息
       	...
          
        try {
          	// 处理消息,msg.target 是 Handler 
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } 
        ...
    }
  	...
}



ActivityThread

应用程序创建的时候,系统会调用 ActivityThread 的 main 方法,创建 Looper 并 调用 loop 方法,使 Looper 开始轮询起来。

// ActiivtyThread 类
public static void main(String[] args) {
	...
	Looper.prepareMainLooper();
	...
	Looper.loop();
}



Handler

用来发送消息(sendMessage)和处理消息(handleMessage)。

Handler 对象被创建的时候,会将 Looper 的 mQueue 赋值给 Handler 的成员变量 mQueue,发送消息 sendMessage 最终调用到了 enqueueMessage 方法,把消息加入到消息队列中。

public class Handler {
  	...
    
    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
  	
  	public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }
  
  	public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
  
  	// 处理消息,由 Looper 触发
  	public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
  	...
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
  
  	public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  
  	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);
    }
  
  	 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;// 将在 handler 本身赋值给 msg 的 target 
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  
}



MessageQueue

消息队列,存放 Message,以链表的方式实现。

消息在加入到队列时,会根据 delay 的时间,插入到队列中合适的位置,保证队列的顺序是按照延迟时间从小到达进行排序。方便在后续获取消息的时候,直接获取到队头消息。

public final class MessageQueue {
  	...
      
    // 将消息加入到队列
 	boolean enqueueMessage(Message msg, long when) {
        ...

        synchronized (this) {
            // 检查Looper及相应的队列是否已经终止
            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 不需要延时 或 msg 需要延时时长小于队列消息的延时时长
              	// 则将 msg 插入消息队列头部
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;// 标记是否需要唤醒
            } else {
                // 根据时间 将消息插入到队列中
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    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;
    }
  	
  	...
  
  	// 获取一个消息
  	Message next() {
        ...
        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指向下一个消息即可
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 如果没有消息,则设置阻塞时长为无限,直到被唤醒
                    nextPollTimeoutMillis = -1;
                }

                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 第一次循环 且 (消息队列为空 或 消息队列的第一个消息的触发时间还没有到)时,
               	// 表示处于空闲状态,获取到 IdleHandler 数量
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // 没有 IdleHandler 需要运行,循环并等待
                    mBlocked = true;// 设置阻塞状态为 true
                    continue;
                }

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

            // 运行 IdleHandler,只有第一次循环时才会运行
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the 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);
                    }
                }
            }

            // 重置 IdleHandler 的数量为 0,确保不会重复运行
            pendingIdleHandlerCount = 0;

            // 在执行 IdleHandler 后,可能有新的消息插入或消息队列中的消息到了触发时间,
            // 所以将 nextPollTimeoutMillis 置为 0,表示不需要阻塞,重新检查消息队列
            nextPollTimeoutMillis = 0;
        }
    }
}



消息类型

Handler 的消息类型有三种:同步消息、异步消息、消息屏障。



同步消息
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);



异步消息
Message message = Message.obtain();
message.what = 1;
message.setAsynchronous(true);// 异步消息设置
handler.sendMessage(message);



消息屏障

添加消息屏障的方法是 @hide 的,需要通过反射调用,该方法会返回该消息的 token ,移除消息屏障需要用到这个 token .

消息屏障用来阻塞消息队列后面的同步消息,而异步消息不受消息屏障的影响。在无消息屏障的情况下,同步消息和异步消息没有区别。

/**
 * MessageQueue类
 * 添加一个消息屏障
 *
 * @hide
 */
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}



内存泄漏

Handler 的内存泄漏原因在于发送延时消息,Handler 发送延时消息到 MessageQueue 中,MessageQueue 持有 Message 引用,而 Message 中又持有 Handler 的引用,Handler 作为 Activity 的内部类 持有 Activity 引用。当 Activity 销毁时,因 MessageQueue 的 Message 无法释放,会导致 Activity 无法释放,引起内存泄漏。



子线程创建 Handler

应用启动时,系统会帮助我们创建 Looper。在子线程中创建 Handler 需要手动调用 Looper.prepare() 和 Looper.loop() 方法。

当子线程消息队列无消息时,结束时需要手动调用 Looper.quit() 或 Looper.quitSafely() 来终止 Looper,否则子线程会卡死在阻塞状态不能停止。

new Thread(){
    @Override
    public void run() {
        Looper.prepare();
        Handler handler = new Handler();
				...
        Looper.loop();
    }
}.start();



Looper 死循环

Looper 死循环,没消息会进行休眠不会卡死,调用 linux 底层的 epoll 机制实现;应用卡死时是 ANR 导致的。



版权声明:本文为linglingchenchen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。