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. 理解Android的handler机制--从应用到原理再到实践
  2. Android开发:Handler异步通信机制全面解析(包含Looper、Message Qu
  3. Android(安卓)Handler主线程和一般线程通信的应用分析
  4. Android(安卓)UI 卡顿及ANR检测原理
  5. 你真的懂Android(安卓)Handler吗?(一)
  6. android应用程序线程的监控
  7. Android面试题2018年整理
  8. android的消息机制 handler looper MessageQueue 关系详解
  9. Android(安卓)组件之一(Service)

随机推荐

  1. android设置动态壁纸 (Wallpaper) 介绍
  2. Unity调用Android的Activity
  3. 《第一行代码》扩展总结
  4. Android 之 BroadcastReceiver自定义广播
  5. [置顶] android应用框架系列二,图形界面
  6. Android拨打电话功能实例详解
  7. OS体系结构
  8. android 中ImageView 无法居中
  9. Android Studio中的“favorites”和“boo
  10. Android init.rc脚本解析