handler消息机制源码级深入全解析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/sxj159753/article/details/51922351

首先我们来看看Handler更新UI线程一般使用

首先要进行Handler 申明,复写handleMessage方法( 放在主线程中)
private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO 接收消息并且去更新UI线程上的控件内容
            if (msg.what == UPDATE) {
                // 更新界面上的textview
                tv.setText(String.valueOf(msg.obj));
            }
            super.handleMessage(msg);
        }
    };
子线程发送Message给ui线程表示自己任务已经执行完成,主线程可以做相应的操作了。
new Thread() {
            @Override
            public void run() {
                // TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值
                try {
                       //do something

                        Message msg = new Message();
                        msg.what = UPDATE;                  
                        msg.obj = "更新后的值" ;
                        handler.sendMessage(msg);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

我们通过画图来了大体解一下handler的消息机制

handler消息机制图解
先看左侧我们通过handler来发消息,这个实在子线程中的。handler可以创建多个,假设我们创建两个handler为handler1和handler2.每个handler都可以向消息队列发消息。handler1发送消息后到消息队列,假设消息为msg1.handler2也会发送消息排在消息队列的msg。但是消息队列是唯一的,消息队列会按照时间排序。消息队列依次从消息队列取消息。之后通过轮询器来取出消息,轮询器实在主线程中的。每个消息通过target属性来找到自己的消息。然后再调用handleMessage()方法中处理结果。

下面我们通过四个类来将handler消息机制弄清楚。Message,MesageQueue,Handler,Looper。

Message

  1, new Message()
  2, Message.obtain();
  3, handler.obtainMessage();

MesageQueue

  存放Message的容器,单链表
       默认:msg的when都是0  后加的放到最前面
            如果when不等于0  按when的值大小进入排序:when的值小的在队列的前面

Handler

  消息处理类
  handleMessage(Message msg)方法,覆盖此方法,做ui的处理

Looper

  轮询器 : 轮询取消息,linux底层管道通讯

Message类

 **//代表message值是什么** 
    public int what;

    public int arg1; 


    public int arg2;

    **//如果信息较多用Obj来作为信息的载体。**
    public Object obj;


    public Messenger replyTo;

    **//  /*package*/为私有的访问权限并不对外提供。**

    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    /*package*/ int flags;
    **//发消息的时间,默认情况下是0。写1000即为等待1000毫秒中再发**
    /*package*/ long when;  
    /*package*/ Bundle data;
    **//target也就是用来区分message的**
    /*package*/ Handler target;     
    **//一个回调接口**
    /*package*/ Runnable callback;   
    **//next其实就是一个单链表**
    /*package*/ Message next;

我们来看一下Message.obtain();中代码

//为了满足语法来new Object();
 private static final Object sPoolSync = new Object();
 private static Message sPool;
 public static Message obtain() {

            synchronized (sPoolSync) {
            //sPool是一个消息池,上面定义了,也就还是一个消息。
                if (sPool != null) {
                    //从消息池中取消息。
                    Message m = sPool;
                    //然后再指向下一个。
                    sPool = m.next;
                    m.next = null;
                    sPoolSize--;
                    return m;
                }
            }
            //如果消息池中没有消息也就是直接创建了一个新的消息。
            return new Message();
        }
我们再来看一下clearForRecycle()这个方法。
//这个方法将所有的属性进行了清零。
void clearForRecycle() {
        flags = 0;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        when = 0;
        target = null;
        callback = null;
        data = null;
    }
    这也就是我们在如下代码中常犯的错误的解释:
//将target=null。msg.what也就不知道到底是哪个target了。发消息也就会报错了。
Message msg = Message.obtain(); 
    msg.what = 1;
    msg.what = 2;
为什么会调用clearForRecycle()这个方法呢?我们看一下下面的方法。也就是在recycle()这个方法中调用了clearForRecycle()方法。
 public void recycle() {
        clearForRecycle();

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                //将静态变量sPool赋值给了next
                next = sPool;
                 //这个又指向了sPool
                sPool = this;
                sPoolSize++;
            }
        }
    }

通过上面的方法中的两句、

     //将静态变量sPool赋值给了next
                next = sPool;
                 //这个又指向了sPool
                sPool = this;

并且结合obtain()中的

     sPool = m.next;
     m.next = null;
我们就可以将两个消息重用为一个消息了。综上 Message类中的方法都跟这个Obtain()方法一样。将消息重用。
ActivityThread执行main();
    //1,
    Looper.prepareMainLooper();

    // 2,
    public static final void prepareMainLooper() {
        //3
        prepare();

        setMainLooper(myLooper());
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }
  // 4
  public static final void prepare() {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //5,,调用的时候Looper.myLooper()-->
    sThreadLocal.set(new Looper());
}
// 6,在handler的默认构造函数中去调用取值
public static final Looper myLooper() {
    return (Looper)sThreadLocal.get();
}
Handler()的构造函数
public Handler() {
        //轮询器的初始化,主线程
        mLooper = Looper.myLooper();

        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // 从轮询器中获取消息队列
        mQueue = mLooper.mQueue;

        //回调初始化为null
        mCallback = null;
    }
通过上面我们需要看两个代码
1,  Looper.myLooper();

     public static final Looper myLooper() {
        //从sThreadLocal取值 ,赋值看 上面##### ActivityThread执行main()
        //ThreadLocal 线程变量。开启多个线程的时候,为每个线程设置一个值。当前线程再去取值的时候,他会取出自己线程的值。而不会取到别的线程设置的值。
        return (Looper)sThreadLocal.get();
    }
2, mQueue = mLooper.mQueue;//获取轮询器中的消息队列
Handler发送Message

1,handler.sendMessage(msg);//发送消息

       public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }

2,sendMessageDelayed(msg, 0);

     public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

3,sendMessageAtTime()

       public boolean sendMessageAtTime(Message msg, long uptimeMillis)
        {
            boolean sent = false;
            //获取消息队列,mQueue的赋值请看Handler的默认构造函数
            MessageQueue queue = mQueue;
            if (queue != null) {
                //把自己的handler和Message绑定,this就是Handler
                msg.target = this;
                //把msg放到消息队列并且完成排序(按时间和顺序)
                sent = queue.enqueueMessage(msg, uptimeMillis);
            }
            else {
                RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
            }
            return sent;
        }

4,sent = queue.enqueueMessage(msg, uptimeMillis);

    消息队列里enqueueMessage方法,
   1,放消息
   2,排序(按消息的时间排序,如果时间一样,后加的在前面
    final boolean enqueueMessage(Message msg, long when) {
        if (msg.when != 0) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }
Looper取消息
 在应用程序启动之前
 ActivityThread的main已经执行好,并且开始等待接收消息
 调用 Looper.loop();//轮询取消息

1,Looper的loop方法

    while (true) {
            //消息队列
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                //找不到对应的handler
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                //处理消息
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);

                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long 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);
                }
                //4,
                msg.recycle();
            }
        }
    }

2, msg.target.dispatchMessage(msg);
调用Handler的dispatchMessage分发消息

 public void dispatchMessage(Message msg) {
    if (msg.callback != null) {// runOnUiThread
        //2.5

        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //3handleMessage
        handleMessage(msg);
    }
}

2.5 handleCallback(msg); 用户调用了runOnUiThread方法调用

a,
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
b,
mHandler.post(action);

public final boolean post(Runnable r)
{
   c,
   return  sendMessageDelayed(getPostMessage(r), 0);
}
 d,

 private final Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

e,
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    //把handler发出去  msg.callback= Runnable
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

//////////上面abcde是通过runOnUiThread方法发送消息的逻辑

取消息
handleCallback(msg);
private final void handleCallback(Message message) {
message.callback.run();//runOnUiThread里写的功能,在主线程运行
}

3, 在主线程中调用Handler的handleMessage(msg)用户覆盖的方法处理消息
处理ui相关的操作
4, msg.recycle();
msg的回收

  public void recycle() {
    synchronized (mPoolSync) {
        if (mPoolSize < MAX_POOL_SIZE) {
            clearForRecycle();

            next = mPool;
            mPool = this;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/sxj159753/article/details/51922351
今日推荐