发布时间:2025-12-09 11:45:53 浏览次数:1
Handler我们都知道,它需要和Looper绑定,当Handler在主线程创建,则会默认绑定主线程的Looper,当是在子线程创建,则需要在Handler的构造方法里传入子线程的Looper的对象。
Handler mHandler;Thread worker = new Thread(){ @Override public void run() { Looper.prepare(); mHandler = new Handler(Looper.myLooper()){ @Override public void handleMessage(Message msg) { ... } }; Looper.loop(); }};private void sendMessage(Object obj){ Message msg = new Message(); msg.obj = obj; mHandler.sendMessage(msg);}上面是在子线程创建一个Handler的demo,通过这个Handler我们可以把消息发送到子线程,让子线程去进行对应的操作。其实到这里只是知道如何用Handler和Looper来实现线程通信,想知道真正的原理,还需要看Looper的源码。
我们先来看看Looper的构造方法,
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}所以Looper其实不暴露构造方法给外部,只通过 prepare()给外部调用,我们再看看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));}到这里就可以看出来,Looper通过public的prepare()方法,构造了一个Looper对象,并保存在sThreadLocal中。我们在不同线程里创建的所有Looper都会保存在它里面。下面是sThreadLocal在Looper里的代码,
// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();每当我们用 Looper.myLooper()获取当前线程的Looper时,就会从 sThreadLocal 中获取。这里涉及到一个有趣的东西,ThreadLocal的使用保证了当前线程只能获取到当前线程创建的Looper,这是ThreadLocal的特性。
当我们调用Looper.loop()之后,当前线程对应的Looper就会循环不断的从MessageQueue中拿消息,并扔给Handler去处理,回过头来看Looper的构造方法,就可以看到MessageQueue对象了。
最后我们再简单看一下Looper.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; ... for (;;) { Message msg = queue.next(); // might block ... try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ... }}到这里就明白,其实Loop就是开始一个无限循环,并从当前线程的Looper里去获取MessageQueue,然后从中读取Message并分发给Handler的过程。当然这里面还有其他几个细节,我们留着下次继续分析,比如1 既然loop()是个无限循环,它为什么不会造成资源无限消耗2 ThreadLocal是怎么做到当前线程只能获取到它自己的Looper的
Looper的原理可以总结如下,· 每个线程都可以创建一个Looper,它会保存在当前线程对应的ThreadLocal里· Handler需要绑定对应线程的Looper对象· 线程在创建完Looper后,需要调用Looper.loop()以让它循环的去读取并分发消息· 跟Looper绑定的Handler会在接收到消息后在对应的线程里处理消息