Handler源码原理分析

来源:互联网 发布:倍福plc编程语言 编辑:程序博客网 时间:2024/05/16 16:18

Android 系统内部是消息机制,什么意思?
说说Handler运行机制?

Handler功能定义:各线程互相通讯用的。常用子线程在做完某事之后然后去更新UI之类。当然两个子线程也能用Handler相互通讯。

本文主要分析两个线程是怎么通信的?通过源码分析原理是什么?

子与主线程通讯用法:

 Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch(msg.what){                case 100:                    String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj;                    mTextView.setText(s);                    Logger.d(s);                  break;                default:                  break;            }        }    };.... new Thread(new Runnable() {                    @Override                    public void run() {                        try {                            Thread.sleep(3000);                            mHandler.sendEmptyMessage(100);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                }).start();

子与子线程通讯用法:

new Thread("thread2"){            public void run() {                Looper.prepare();                mHandler = new Handler(){                    @Override                    public void handleMessage(Message msg) {                        super.handleMessage(msg);                        String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj;                        Logger.d(s);                    }                };                Looper.loop();            }        }.start();

发送时不变,还是用handler对象直接发送空消息,或者创建消息发送。
就多了Looper.prepare()Looper.loop(); 等下会讲为什么。

需要分析的类

Message:消息对象,用到存放数据,和下一个Message对象
MessageQueue:字面意思消息队列,但其实它并不是队列,不过确实是负责消息的插入和取出
Handler:给用户层用来创建和发送消息,和处理收到的消息
Looper:不断循环取消息,和调用Handler处理消息
(说实话,这种看别人简单的总结根本不能理解,肯定想问,这到底是Handler发送处理消息,还是Looper发送处理消息?等等疑问。这都个人理解,还是看源码说吧)

先来看传递的对象Message,有几个常用属性。

**Message.class**    public int what; //区分消息的标识,在发送消息和接收时确认    public int arg1,arg2; //可以传递两个int值    public Object obj; //其它想要传递的对象

然后直接进Handler 类 mHandler.sendEmptyMessage(100);看看发送时做了什么。

**Handler.class**public final boolean sendMessage(Message msg){        return sendMessageDelayed(msg,0);}...//延迟多少毫秒发送public final boolean sendMessageDelayed(Message msg,long delayMillis){        if(delayMillis< 0){            delayMillis=0;        }//        SystemClock.uptimeMillis()系统开机时间        return sendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);}//在一个准确时间发送public boolean sendMessageAtTime(Message msg,long uptimeMillis){        MessageQueue queue=mQueue;        if(queue==null){            RuntimeException e=new RuntimeException(                this+" sendMessageAtTime() called with no mQueue");            Log.w("Looper",e.getMessage(),e);        return false;        }        return enqueueMessage(queue,msg,uptimeMillis);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

可以看到,不管是sendMessage,还是sendMessageDelayed等……最后都是调用了sendMessageAtTime,然后enqueueMessage,又分发给了queue.enqueueMessage(msg, uptimeMillis),然后发现有个MessageQueue queue,看在哪赋值?在Handler构造函数中,Handler构造函数也很多,最终进:

**Handler.class**public Handler(Callback callback, boolean async) {        ...        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

观察到mQueue是从Looper中拿来的,如果Looper为空,就throw new RuntimeException(),那进Looper.myLooper();

 **Looper.class** public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }

看sThreadLocal赋值

 **Looper.class** // sThreadLocal.get() will return null unless you've called prepare().    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

直接在初始化就定义了,并且static final,说明一个进程只有一个,并无再赋值,然后看ThreadLocal是什么?
ThreadLocal 定义:与线程想关的数据存储类。

ThreadLocal 使用

ThreadLocal<Boolean> mThreadLocal=new ThreadLocal<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mThreadLocal.set(true);        Logger.d(Thread.currentThread() + " " + mThreadLocal.get());        new Thread(new Runnable() {            @Override            public void run() {                Logger.d(Thread.currentThread() + " " + mThreadLocal.get());                mThreadLocal.set(false);                Logger.d(Thread.currentThread() + " " + mThreadLocal.get());            }        }).start();    }**log**D/: Thread[main,5,main] trueD/: Thread[Thread-221,5,main] nullD/: Thread[Thread-221,5,main] false

用法简单。只有get、set、remove。可以看到,主线程set(true),get()是true。在子线程中,第一次get,因为没有set,直接为null。然后set(false),取出false,说明在子线程中,并没有get到主线程set的值。看看实现:

**ThreadLocal.class**public class ThreadLocal<T> {    public T get() {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values != null) {            Object[] table = values.table;            int index = hash & values.mask;            if (this.reference == table[index]) {                return (T) table[index + 1];            }        } else {            values = initializeValues(currentThread);        }        return (T) values.getAfterMiss(this);    }    public void set(T value) {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values == null) {            values = initializeValues(currentThread);        }        values.put(this, value);    }    ...    Values values(Thread current) {        return current.localValues;    }     static class Values {        private Object[] table;     }}

Values 为ThreadLocal 的静态内部类,可以看到,数据最终存储的地方在Thread对象本身里的localValues.table数组里,ThreadLocal只是判断线程,然后把数据有序在放在table里,这里用了一个高效存储算法,table[i]为key,[i+1]为value,大概就是这样意思,这样可能效率性能会好吧!
如果Thread对象本身Values存储怎么办?实现这个和线程相关的存储数据有很多方法,自己也可以实现,下面自己实现一个:

//自己写的ThreadLocalpublic class ThreadLocal<V> {    private Map<Long,V> mMap;    public ThreadLocal() {        mMap = new HashMap<>();    }    public V get(){        long id = Thread.currentThread().getId();        return mMap.get(id);    }    public void put(V value){        long id = Thread.currentThread().getId();        mMap.put(id,value);    }}

用线程唯一标识为Key就行,效率可能没google写的ThreadLocal好。
再回到Looper.myLooper()方法。

**Looper.class**public static @Nullable Looper myLooper() {        return sThreadLocal.get();}

这里线程取到的肯定为空,唯一赋值方法在

public static void prepare() {    prepare(true);}private static void prepare(boolean quitAllowed) {    if (sThreadLocal.get() != null) {         throw new RuntimeException("Only one Looper may be created per thread");    }    sThreadLocal.set(new Looper(quitAllowed));}

所以我们在子线程初始化Handler时,才要Looper.prepare();为了实例化Looper,而且每个线程还只能调用一次,那我们的主线程在那调用的呢?那就要到ActivityThread.class看看了,ActivityThread就是每个应用的大门,应用的main函数。activity、service、broadcasts等都是在这里启动。

public final class ActivityThread {    ...    public static void main(String[] args) {        ...省略代码若干         Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        ...        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }    final Handler getHandler() {        return mH;    }}

可以看到,有熟悉的java的main,new Handler()之前调用Looper.prepareMainLooper();这个内部也是prepare(),而且这个Handler处理这个应用系统所有Message,Activity生命周期、createService等都是这个handler进行分发。这个类以后要好好研究,所以为什么这就是android系统内部的消息机制,无论点击按钮,启动页面,都是通过Handler进行发送消息然后分发到各个类处理。

Ok,创建了Looper,创建了MessageQueue,然后看MessageQueueenqueueMessage方法

boolean enqueueMessage(Message msg, long when) {  ...    synchronized (this) {        ...        msg.markInUse();        msg.when = when;        Message p = mMessages;//单链表的第一个message        boolean needWake;//是否需要唤醒,如果链表中没有待处理的message,主线程将睡眠        if (p == null || when == 0 || when < p.when) {            // New head, wake up the event queue if blocked.            msg.next = p;            mMessages = msg;            needWake = mBlocked;//上一个message为空,说明这是要处理message队列的第一个,将唤醒主线程,这里会为true        } else {            needWake = mBlocked && p.target == null && msg.isAsynchronous();            //这一段逻辑是取出链表中的最后一个Message prev,把新的msg赋值给它的next            Message prev;            for (;;) {                prev = p;                p = p.next;                if (p == null || when < p.when) {                    break;                }                if (needWake && p.isAsynchronous()) {                    needWake = false;                }            }            msg.next = p; // invariant: p == prev.next            prev.next = msg;        }        // We can assume mPtr != 0 because mQuitting is false.        if (needWake) {            nativeWake(mPtr);//为true,将唤醒主线程        }    }    return true;}

这里可以看到,当前msg是赋值给最后一个msg的next,这里像是单链表。如图:
message链表
Message mMessages;即是链表第一个msg,也就是最快将要处理的msg(如果不为空的话)
这里有两种情况,else表示链表不为空,通过for循环,定位到最后一个msg,然后把新传递进来的msg赋值给最后一个msg的next。这就算是添加成功了。if表示链表为空(如果你进入一个新页面,不做任何操作,msg队列将会被处理完,然后主线程会睡眠,当有新的msg进来时,要唤醒主线程) nativeWake(mPtr);是个native方法,唤醒主线程。

到此,msg就算是添加到队列中了,然后在哪里处理呢?
这就要看ActivityThread中main方法最后调用了Looper.loop();因为这个会阻塞线程,所以要放在线程最后调用。

 public static void loop() {        final Looper me = myLooper();        ...        final MessageQueue queue = me.mQueue;        ...        for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                return;            }            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            msg.target.dispatchMessage(msg);            if (logging != null) {                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);            }            ...        }    }

简单理解就是循环从MessageQueuenext();方法取msg,为空将结束循环,否则msg.target.dispatchMessage(msg);这里msg.target就是创建msg时的handler,进
dispatchMessage方法。

**Handler.class** public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

如果msg有callback,这个callback是Runnable,否则检查mCallback不为空,调用mCallback.handleMessage(msg),最后调用自身的handleMessage(msg);,我们一般都是直接new Handler(),重写handleMessage(msg)方法。可以看见传递callback也是可以的。这里比较简单。

然后重点看queue.next(),也就是取出msg方法

**MessageQueue.class** Message next() {        int nextPollTimeoutMillis = 0;        for (; ; ) {            ...            nativePollOnce(ptr, nextPollTimeoutMillis);            ...            synchronized (this) {                // Try to retrieve the next message.  Return if found.                final long now = SystemClock.uptimeMillis();                Message prevMsg = null;                Message msg = mMessages;                ...                if (msg != null) {                    // Got a message.                    mBlocked = false;                    if (prevMsg != null) {                        prevMsg.next = msg.next;                    } else {                        mMessages = msg.next;                    }                    msg.next = null;                    msg.markInUse();                    return msg;                } else {                    // No more messages.                    nextPollTimeoutMillis = -1;                }                ...            }        }    }

大致为mMessages是否为空,不为空就把return mMessages出去,并且next标记清掉,给mMessages = msg.next;赋于下一个msg。为空的话nextPollTimeoutMillis = -1;下次循环中,
nativePollOnce(ptr, nextPollTimeoutMillis);为-1时将睡眠。

而且我们还发现Printer logging = me.mLogging;会调用Printer.println(String n),说明我们可以监听到msg的处理,例:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            Looper.myLooper().setMessageLogging(new Printer(){                @Override                public void println(String x) {                    Log.d("TAG",x);                }            });            Looper.myLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {                @Override                public boolean queueIdle() {//消息队列处理完毕回调,return false 将只能监听一次结束                    return true;                }            });        }

addIdleHandler 可以监听消息队列处理完毕,setMessageLogging可以监听消息处理前后,打打log:

D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82fD/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179: 0D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f: 0D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1fD/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 101D/: <<<<< Finished to Handler (android.app.ActivityThread$H) {b0be8e6} nullD/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null: 6D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} nullD/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82fD/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 100

总结:
Handler消息机制就是,主线程不断循环(Looper.loop)检查有无待处理msg(queue.next),有就处理(handler.dispatchMessage()),没有就睡眠(nativePollOnce())。当子线程发送了一个msg时(queue.enqueueMessage),唤醒主线程(nativeWake()),主线程就接着处理(queue.next),从而实现了子线程与主线程通信。原理也就是子线程与主线程共同操作一个队列,一存,一取。原理简单粗暴,不过nativePollOnce睡眠、nativeWake唤醒、两个为native方法,肯定不是sleep那么简单。

原创粉丝点击