Handler机制

从接触Handler到现在接近4年,慢慢深入 慢慢摸索,直到今天看完何红辉的源码讲解之后终于知道具体

最初了解到handler是因为几个异常
第一个是 子线程不能操控UI线程的控件 需要用handler.post(Runnable) 将其推到主线程消息队列中执行
第二个是 直接在子线程中new handler()时抛出 cann't create handler inside  thread that has not called Looper.prepare()  第一次知道有个Looper 这东西

好的 先上图
Handler机制_第1张图片

各个部件职能说明:
Thread:线程对象 申请一个线程运行空间,独立运行子线程
Handler :处理者 提供给外部的一个句柄,用来操控消息队列 和循环器   并执行消息具体处理
MessageQueue: 消息队列  用于存放消息 采用队列先进先出原则 
Looper : 循环器  内部是一个死循环,循环读取MessageQueue中的消息,如果消息队列为空 那么阻塞

解释一下图:
1.线程中有保留handler对象的引用
2.handler中保留looper和MessageQueue的引用
3.Looper中保留MessageQueue的引用

保留引用的作用就是可以调用 

而这个机制很重要的一点就是 :
Thread中的Handler对象被公开了, 也就是说在外部可以获取此线程的handler, 那么 就可以操控此线程的Looper和MessageQueue

有这个基础 我们讲下 消息处理过程(sendMessage,handleMessage过程 )
1. 首先由handler向MessageQueue中推送一条消息
2. 然后Looper阻塞的线程恢复运行,读取MessageQueue中的消息,将消息发给Handler (这里有个问题 Looper并没有handler的引用 ,如何将消息发给handler)继续等待/处理下一条消息
3. Handler调用我们自定义的处理方法处理消息


开始讲代码

一、首先看线程创建过程(以主线程为例 因为主线程中会创建Looper)

线程创建时主要做了这三件事 (主要讨论handler相关)

Thread()
{
    Looper.prepare();                //在 线程中创建一个循环器looper
    handler=thread.getHandler();     //在线程中创建Handler()
    Looper.loop();                   //开始死循环
}


1.1 首先看Looper.prepare() 主要做了什么
public static void prepare()
{
    //Looper中保留了线程的引用 即这里的threadLocal
    if(threadLocal.get()!=null)
    {
        //判断当前线程有没有创建过Looper   get()方法就是获取looper对象
        throw new RuntimeException("only one Looper may be created per thread");
    }
    threadLocal.set(new Looper);
}


很简单, prepare函数只简单地创建了一个Looper 

1.2 然后是 get Handler()函数 
Handler 是 直接new出来的 我们看下它的构造函数
public Handler()
{
    mLooper=Looper.myLooper();         //Looper中提供静态方法 myLooper 获取当前looper
    if(mLooper==null)
    {
        throw new RuntimeException("Can't not create handler inside thread that has not called Looper.prepare");
    }
    mQueue=mLooper.mQueue;
    mCallback=null;
}


很明显 handler中有 Looper 和MessageQueue的引用 mLooper 和 mQueue 在构造函数中初始化了这两个引用  
然后中间的那个异常 就是说 必须要调用Looper.prepare()预先创建好Looper   否则 后面 从Looper中获取mQueue 时肯定会报空指针异常
这里主要就是创建handler 并初始化两个引用


1.3  创建Thread的最后一步 : Looper.loop(); 执行循环
public static void loop()
{
    Looper me=myLooper();  //myLooper函数 同上
    if(me==null)
    {
        throw new RuntimeException("No Looper ; Looper.prepare wasn't called on this thread");
    }
    MessageQueue queue=me.mQueue;   //同上 获取消息队列对象
    while(true) //死循环 读取消息
    {
       Message msg= queue.next();  //获取 下一条消息  如果没有就阻塞
        //判断消息是否为空 
        if(msg!=null)
        {
            if(msg.target==null)
            {
                //target是发送消息的handler对象(handler 发送消息的同时 把自己也保存在了消息对象里面), 如果发送这个msg的handler不存在了(被销毁)这个消息就不处理了
                return ;
            }
            msg.target.dispatchMessage(msg);  //将消息转发给handler处理 (这里有点绕  handler把消息发过来  这里又把消息发回 handler  有病吧……  呵呵 后面再解释)
            msg.recycle();         //消息对象回收 
        }
    }
}



以上 便是建立线程时 初始化handler机制的三个步骤:
1 创建Looper 
2 创建Handler
3 启动Looper;

是不是感觉少了什么? 怎么没找到MessageQueue创建在哪?
    其实MessageQueue是包含在Looper里面的 创建Looper的同时就创建了MessageQueue 上面获取MessageQueue 都是通过Looper获取的

其实到现在 大部分流程都已经清楚了  那么  开始解释上面的 绕吧!
不懂得地方就是这句  msg.target.dispatchMessage(msg); 
我们先看下Message对象里面到底有什么东西
Message
{
   Handler target;           
    //target是handler类型 其实也就是发送此消息的那个handler 
    //哈哈  还记得上面的问题 Looper内没有handler的引用 怎么将消息发给handler么?答案就在Message内 它保存了发送方的引用
    //另外记得handler的一个方法么:handler.obtainMessage().sendToTarget() 


 Runnable callback; //Runnable 对象 想必是要运行什么 先记着 Message next ; //下一条消息 消息队列是链式存储的 int arg1, arg2 ,what ; Object obj; ...............}



那么 上面就是调用了handler的dispatchMessage方法
public void dispatchMessage(Message msg)
{
    //好的 这里就用上了 上面的Runnble类型的Callback
    if(msg.callback !=null)
    {
        //当msg中的Callback不为空时就调用msg中的Runnale callback
        handleCallback(msg);
    }else
    {
        if(mCallback!=null)
        {
            if(mCallback.handleMessage(msg)){
            {
                   return ;
            }
        }
        //如果Message没自带处理方法就调用 handler的handleMessage方法 这个方法我们一般会覆盖它
        handleMessage(msg);
    }
}

private final void handleCallback(Message message)
{
    message.callback.run();
}
public void handleMessage(Message msg)
{
    //这个方法我们一般会覆盖它 用它来处理我们发送的信息
}



到这里 我们还是不清楚 Runnable是在哪用到的 那么 提示下 
我们使用handler有两种方式:
(1) handler.sendMessage();
(2) handler.post(Runnable);
哈哈 再知道那个Runnable callback 哪里来的吧  这两种方式就是上面的if /else
其实这两种方式是一样的 都是通过sendMessageDelay()方法将Message对象发送到MessageQueue中 , sendMessage发送的是个包装好的Message对象  而post方法是将Runnable封装成了Message对象 


好的 还剩最后一个问题
handler将消息发给消息队列   Looper取出来 又分给handler  有病吧!!! 还不如直接给handler处理……

我们分析下  
我们利用handler主要是为了跨线程传递消息 ,
而这里handler将消息发给消息队列后 其实就是一个切换线程的过程 由原来的线程转到了handler所在线程的内部looper循环  ,
如果直接交给handler处理就还是在原来的线程中操作。

另外通过消息队列一转换 由同步过程变成异步过程 
一是解耦 
二是 解放了handler  handler不必直接进行处理操作(如果这个操作很耗时 那么多次调用handler可能会出现异常情况)

好了    handler机制到此结束 此过程部分为主观臆断 如果有什么不对 麻烦请给我指正 












你可能感兴趣的:(android,基础,机制,handler,Looper,android,MessageQueue)