Handler消息传递机制之Looper简介

Android的消息处理有四个核心类:Handler、Looper、Message、MessageQueue,都在android.os包中。

线程的魔法师 Looper

Looper的字面意思是“循环器”,"轮询器",它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单,代码如下:

publicclass LooperThread extends Thread {
    @Override
publicvoid run() {
// ①.将当前线程初始化为Looper线程
        Looper.prepare();
        public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                case 0:
                        break;
                default:
                        break;
                }
 }      
// ②.开始循环处理消息队列
        Looper.loop();
    }
        }

通过上面两行核心代码,普通线程就升级为Looper线程了!!!看看这两行代码各自做了什么。


1)Looper.prepare()


通过上图可以看到,现在你的线程中有一个Looper对象,它的内部维护了一个消息队列MQ。注意,一个Thread只能有一个Looper对象,为什么呢?咱们来看源码。

源码。

public  class  Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
privatestaticfinal ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
    Thread mThread;
// 。。。其他属性

// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

// 我们调用该方法会在调用线程的TLS中创建Looper对象
publicstaticfinalvoid prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
thrownew RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
// 其他方法
}

通过源码,prepare()背后的工作方式一目了然,其核心就是将looper对象定义为ThreadLocal,其实就是将一个唯一的Looper对象给添加到ThreadLocal中.


2)Looper.loop()

调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。其源码分析如下:

publicstaticfinalvoid loop() {
        Looper me = myLooper();  //得到当前线程Looper
        MessageQueue queue = me.mQueue;  //得到当前looper的MQ
        Binder.clearCallingIdentity();
finallong ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
            Message msg 
            Message msg = queue.next(); // 取出message
if (msg !=null) {
if (msg.target ==null) {
// message没有target为结束信号,退出循环
return;
                }
             }
// 日志。。。
if (me.mLogging!=null
me.mLogging.println(">>>>> Dispatching to "+ msg.target +""+ msg.callback 
+": "+ msg.what);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
                msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!=null) me.mLogging.println("<<<<< Finished to"+ msg.target +" 
     "+ msg.callback);     
finallong newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
                    Log.wtf("Looper", "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);
}
                }
// 回收message资源
                msg.recycle();
            }
        }
    }

除了prepare()和loop()方法,Looper类还提供了一些有用的方法,比如:

Looper.myLooper()得到当前线程looper对象:

publicstaticfinal Looper myLooper() {
// 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
return (Looper)sThreadLocal.get();
}

getThread()得到looper对象所属线程:

public Thread getThread() {
return mThread;
}

quit()方法结束looper循环:

publicvoid quit() {
// 创建一个空的message,它的target为NULL,表示结束循环消息
        Message msg = Message.obtain();
// 发出消息
        mQueue.enqueueMessage(msg, 0);
}

到此为止,你应该对Looper有了基本的了解,总结几点:

1.每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal;

2.Looper内部有一个消息队列loop()方法调用后线程开始不断从队列中取出消息执行;

3.Looper使一个线程变成Looper线程。

那么,我们如何往MQ上添加消息呢?Handler详细讲解,请待下回分解!

知行办公,专业移动办公平台

https://zx.naton.cn/

原创团队:

【总监】十二春秋之,3483099@qq.com;
【Master】zelo,616701261@qq.com;【运营】运维艄公,897221533@qq.com;
【产品设计】流浪猫,364994559@qq.com;【体验设计】兜兜,2435632247@qq.com;
【iOS】淘码小工,492395860@qq.com;iMcG33K,imcg33k@gmail.com;
【Android】人猿居士,1059604515@qq.com;思路的顿悟,1217022114@qq.com
【java】首席工程师MR_W,feixue300@qq.com;【测试】土镜问道,847071279@qq.com;
【数据】fox009521,42151960@qq.com;【安全】保密,你懂的。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值