android handler 和Looper 的理解

来源:互联网 发布:淘宝商家等级划分 编辑:程序博客网 时间:2024/05/16 06:25

android 系统当中,我们都知道不能把请求网络的线程放在主线程中,或者,任何耗时的操作都不应该在主线程中进行,所以,那些耗时的操作都被放在了子线程中进行。因此,android 官方提出了一种主副线程的交互机制(handler)。
关于handler的使用方法,大家去百度上搜下就可以了。本文主要说下handler机制的原理。
大家都知道,handler属于主副线程交互(其实不然,线程自己也可以给自己做交互)。我大致总结handler机制:hanlder机制主要由以下几个重要的类构成:
1.handler。
2.Looper。
3.Message
4.和MessageQueue
这四个类基本组成了handler机制,大致描述为:hanlder负责发送,分发和处理消息机制,是整个消息的负责人,Looper类是一个消息泵,完成消息循环,不断的从MessageQueue中获取属于这个handler的Message,handler获取到对应的Message后,再进行Message的处理。
接下来,我从源代码里面,挑出几个比较重点的部分来阐述这个机制的原理:
1.handler的创建:

    public Handler(Looper looper) {        //初始化构建消息系统参数              mLooper = looper;              mQueue = looper.mQueue;              mCallback = null;   }    public Handler() {        //初始化构建消息系统参数              mLooper = Looper.myLooper();              mQueue = mLooper.mQueue;              mCallback = null;  }

平时使用handler的时候,就有两种方式:一种是所谓的传入Looper,一种是空构造。如果只是做主副线程交互的话,你会发现,好像两种方式都是差不多的。其实看了上述源代码之后,你就会明白,如果默认空构造,Looper也可以自动生成。从handler的创建上,我们明白了,一个handler必定要对应一个Looper,因为handler要得到MessageQueue的引用,而MesssageQueue又是放在Looper中的。
那么,Looper.myLooper的函数又长什么样子呢?

   public static Looper myLooper() {        return sThreadLocal.get();    }    public static void prepare() {     if (sThreadLocal.get() != null) {              throw new RuntimeException("Only one Looper may be created per thread");     }     sThreadLocal.set(new Looper());}//存储线程的局部变量static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

可以看到,Looper.myLooper其实也返回了一个Looper实例,这里ThreadLocal类,应该是这样一种解释: ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据。对于Handler来说,它需要获取当前线程的Looper,很显然Looper的作用域就是线程并且不同线程具有不同的Looper,这个时候通过ThreadLocal就可以轻松实现Looper在线程中的存取。
如果大家不清楚,可以仔细查看这篇博客http://blog.csdn.net/singwhatiwanna/article/details/48350919(任主席的技术博客)
我们在主线程的handler创建的时候,也喜欢用Looper.getMainLooper(),这个方法的源代码是什么呢?

     public synchronized static final Looper getMainLooper() {        return mMainLooper;    }     public static final void prepareMainLooper() {        prepare();        setMainLooper(myLooper());        // other codes...    }

mainLooper 是专门属于主线程的Looper,可以看到,创建方式其实和myLoopper是一样的,只是换了一个名字而已。
所以,总结起来来说,hanlder创建的最主要问题,就是找到自己对应的Looper,handler方可正常运行。
2.消息发送和消息循环:
handler发送消息有两种方式:sendMessage和post,这两种方式一种是同步的,一种异步的。hanlder发送了消息了之后,就会把message对象加入message队列中。

 final boolean enqueueMessage(Message msg, long when) {              Message p = mMessages;              if (p == null || when == 0 || when < p.when) {                 msg.next = p;                 mMessages = msg;              }              else {                     Message prev = null;                     while (p != null && p.when <= when) {                            prev = p;                            p = p.next;                     }                     msg.next = prev.next;                     prev.next = msg;              }              ……  }

接下来,我们的Looper就可以进行消息的循环,调用Looper.loop()方法:

 public static void loop() {       MessageQueue queue = me.mQueue;       while (true) {              Message msg = queue.next(); // might block              if (msg != null) {                     if (msg.target == null) {                            // No target is a magic identifier for the quit message.                            return;                     }                     //派发消息 到target(Handler)            msg.target.dispatchMessage(msg);            //回收Msg到msgPool                     msg.recycle();              }       }  }

可以看到,hanlder负责发送Message(进入队列的操作),然后Looper不断地从MessageQueue中取出Message(出队列的操作),一进一出,正好解决问题。
3.消息处理
上述代码中:msg.target.dispatchMessage(msg),这条语句其实就是已经开始分发消息了。我们来看看分发消息的源代码:

 public void dispatchMessage(Message msg) {       //首先判断runnable对象       if (msg.callback != null) {              handleCallback(msg);       }       else {              //整个消息系统的回调函数 可以不用实现自己Handler              if (mCallback != null) {                     if (mCallback.handleMessage(msg)) {                            return;                     }              }              //消息处理 通常交给Handler派生类              handleMessage(msg);       }  }

dispatchMessage方法主要做两件事情:1.判定提交的Message是不是Runnable,也就是是不是异步处理的2.如果不是异步的处理的,就是同步处理消息,调用handleMessage(msg),所以大家明白了开发的时候.3如果是异步处理,handleCallback(msg)。

所以大家现在从源代码的角度,可以看到handler到底是一个什么样的存在了吧。下面给出handler的图解,帮助大家总结handler的原理:
这里写图片描述

其实,我经常觉得hanlder是在自发自收。但是正式这样一种机制,实现线程之间的交互。
————————-Q & A —————————————

Q:既然说handler是自发自收,那线程之间的交互如何而来?
A:每个hanlder都属于一个线程,比如有主线程的handler0,子线程1的handler1,子线程2的handler2,我们需要子线程1给主线程传递消息,那么,在子线程1创建的时候,传入handler作为参数就可以了。

Q: hanlder 机制的消息传递是共享内存吗?
A: 可以这样说,其实,looper是通过ThreadLocal得来的,前面也说过了,ThreadLocal就是线程内部数据存储的类,每个线程都只能得到自己Looper,得到了Looper,就得到了MessageQueue,所以,消息传递机制应该是共享内存实现的。

Q:一般使用子线程给主线程发送消息,那主线程怎么给子线程发送消息呢?
A:简单,在子线程中,创建hanlder,在主线程中得到handler,然后通过这个hanlder就可以实现主线程发送消息给子线程了。可以查看这篇链接:http://www.bkjia.com/Androidjc/893149.html,讲了包括线程怎么自己给自己交互的方式。

Q:子线的handler可以空构造吗?
A: 不可以,子线程必须这样写:

public void run(){  Looper.prepare();                mHandlerTest1=new HandlerTest1(Looper.myLooper());                Message message = new Message();                message.obj = "子线程发送的消息Hi~Hi";                mHandlerTest1.sendMessage(message);                Looper.loop();                }

Q: HandlerThread 是什么东东?
A:上一个问题说了,子线程中的handler是不可以空构造的,必须通过上面Answer中的方式来,其实我们也可以通过HandlerThread来,andlerThread 继承自Thread,内部封装了Looper。我们也可以使用这个类来构造子线程的Looper。
创建一个HandlerThread,即创建了一个包含Looper的线程。

HandlerThread handlerThread = new HandlerThread(“leochin.com”);
handlerThread.start(); //创建HandlerThread后一定要记得start()
获取HandlerThread的Looper

Looper looper = handlerThread.getLooper();
创建Handler,通过Looper初始化

Handler handler = new Handler(looper);

1 0
原创粉丝点击