Android消息机制之 Looper、Handler、Message的关系和运行

在网上看了好多介绍这铁三角的文章,有所感悟,但是要想真正消化,还是要自己动手记录一下。首先推荐一篇文章:

http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html  

这篇文章基本上把我的理解讲完了,所以大家可以直接飞进去,看图文并茂哦。另外声明,文章引用源码代码块均转自上面推荐文章。

下面讲讲自己的理解,看完大牛的文章,总得能讲出自己的感悟才行呀。

主人公出场!

1、首先,Looper(为什么我一看见这个词,就想到了RNG的上单Looper!果然世界上最遥远的距离,是你在讲代码,我却理解成了LOL = =)我们可以称之为泵,循环者,balabala……它被设计用来使一个普通线程变成Looper线程因为它的任务就是不停的循环体内的队列,取出消息,找出消息target,让它执行我们形象一点,Looper就是外卖小哥,他的任务就是不停地拿出订单(队列),找到订单上的人(target),让此人拿走外卖(执行操作)。当我们需要让一个线程不断循环执行一系列有序操作时,就可以用到Looper,而你只需要敲两行代码:

<span style="font-size:14px;">public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();
        
        // ...其他处理,如实例化handler
        
        // 开始循环处理消息队列
        Looper.loop();
    }
}</span>
轻松+愉快有木有!

我们需要知道,每个线程只能有一个Looper,即每个山头只能有一个大王。每个Looper都有一个队列,即每个大王麾下都有一批小喽啰。

上Looper源码:

<span style="font-size:14px;">public class Looper {
    // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    // Looper内的消息队列
    final MessageQueue mQueue;
    // 当前线程
    Thread mThread;
    // 。。。其他属性

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

    // 我们调用该方法会在调用线程的TLS中创建Looper对象
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            // 试图在有Looper的线程中再次创建Looper将抛出异常
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    // 其他方法
}</span>
可见Looper是绑定当前线程的。有了Looper线程,怎么往里面塞任务,且看Handler发威。

2、Handler,有人称之为“异步处理大师”,它的引用可以在任何线程发送消息,并在new它的地方,处理自己的消息。形象的理解,就像我们披萨公司(Handler)在不同省市,有很披萨分店(引用),我们都属于披萨集团(Handler)。一旦某省声明,我们需要一种全新的披萨(消息),分店赶紧通知总公司(发送消息),总公司就加紧研发(获得消息并处理)。

我们需要知道,如果建立Handler的时候,没有指定Looper,那它默认绑定当前线程的Looper。Handler内心OS:我就是墙头草,咬我呀!

上源码:

<span style="font-size:14px;">public class handler {

    final MessageQueue mQueue;  // 关联的MQ
    final Looper mLooper;  // 关联的looper
    final Callback mCallback; 
    // 其他属性

    public Handler() {
        // 没看懂,直接略过,,,
        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());
            }
        }
        // 默认将关联当前线程的looper
        mLooper = Looper.myLooper();
        // looper不能为空,即该默认的构造方法只能在looper线程中使用
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
        mQueue = mLooper.mQueue;
        mCallback = null;
    }
    
    // 其他方法
}</span>
可见Handler会直接把关联Looper的队列当作自己的,一有消息,就发送到该队列上,当真是没把自己当作外人!所以当我们在主线程New了一个Handler以后,整个“寄生体系”就建立了。

Handler中的核心方法是,dispatchMessage(Message msg)sendMessage(Message msg)。后者由Handler调用(为啥先说后者,我,我任性),当我们调用handler.sendMessage(msg)的时候,首先,msg会把target指定为此handler,所以在Looper轮询消息队列,到此条msg的时候,才能找到执行者—handler。

前者由Looper调用,也就是在:

<span style="font-size:14px;"> Looper.loop();</span>

它的核心代码是:

msg.target.dispatchMessage(msg);
看到这里,你明白为什么我要先说后者,再说前者了吧,哼(傲娇)!

3、Message自然就是任务了,可说的不多,但有两点让我大呼学到了,先看第一点:

我想象的Message是这样用:

<span style="font-size:14px;">Message msg = new Message();
msg.what = XX;
msg.obj = XX;</span>
而实际上,源码中的它是这样用:

<span style="font-size:14px;">Message msg = handler.obtainMessage();
msg.what = xxx;
msg.obj  = xxx;</span>
因为调用obtainMessage方法,会先看消息池MessagePool里有没有空闲消息,有就复用,没有再new新的,这样可以节省内存,对于经常OOM的小内存机型来说,简直是约翰福音啊有木有!

再说第二点,出自最开始说的大牛文章,传送门在文章开头。

如果你的message只需要携带简单的int信息,请优先使用Message.arg1和Message.arg2来传递信息,这比用Bundle更省内存,约翰福音2.0~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值