android Handler 工作原理分析(一)

来源:互联网 发布:网络修复大师手机版 编辑:程序博客网 时间:2024/06/05 22:29

今天学习了一下android  Handler源码,同时也总结了一下网上其他朋友的分享。在这里,把今天学习到的一些东西跟大家分享一下。

Handler具体的作用就不做多说,网上一搜一大堆。

首先,跟Handler工作紧密相关的有几个类

Message(消息对象,子线程和UI线程通信的载体)。

Looper 负责消息分发  没一个looper都是一个跟一个线程绑定的,是一个线程局部变量,这个会在后续的代码分析中具体去讲  

MessageQueue 存放消息的容器.


我们先从Handler的构造函数看一下这个类

    public Handler() {       //这段代码什么意思没看明白        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        //获取一个looper对象,在这里Handler和looper建立了联系,后面在讲了looper的源码时会具体分析        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }       //这里初始化消息队列        mQueue = mLooper.mQueue;      //不实现Handler.callBck接口,这里赋为空             mCallback = null;    }



上面的代码创建了Handler,我们接着按照Handler我们可见的路线去分析一下,下面我们看下

sendMessage这个方法

public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        //之前从looper对象中获取到的消息队列        MessageQueue queue = mQueue;        if (queue != null) {            //在这里,message对象和handler建立了联系            msg.target = this;            这里将新来的消息排队到消息队列中,放到消息队列的最后            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;}
public static void prepare() {       //这里大家可以看到,如果当前线程已存在这么一个变量,这里是会异常,所以looper的 prepare()方法不要重复去调用        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        //这个时候放进去的        sThreadLocal.set(new Looper());   }



当我们自己new一个message对象作为参数调用sengMessage方法的时候,最终调用到的都是上面这个方法。

消息发送出去后并不是直接就由handler调用handleMessage处理,这时候looper就工作了(其实他的工作就没停过)。


接着我们来看下looper如何工作的

之前我们在handler的构造方法中看到

mLooper = Looper.myLooper();

我们来看看这个方法

 

public static Looper myLooper() {        return sThreadLocal.get();    }


很简单,获取当前线程的局部变量

这个变量是什么时候放进去的呢


//这里调用prepare();

public static void prepareMainLooper() {        prepare();        setMainLooper(myLooper());        myLooper().mQueue.mQuitAllowed = false;    }


而这个方法在Activity初始化的时候会调用一次,也就是说我们的looper是主线程也就是UI线程初始化的,前提是我们的Handler是在UI线程中初始化的,当然我们大部分情况下都是这么做的。

public static void loop() {        Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        MessageQueue queue = me.mQueue;                // Make sure the identity of this thread is that of the local process,        // and keep track of what that identity token actually is.        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();                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;                }                long wallStart = 0;                long threadStart = 0;                // This must be in a local variable, in case a UI event sets the logger                Printer logging = me.mLogging;                if (logging != null) {                    logging.println(">>>>> Dispatching to " + msg.target + " " +                            msg.callback + ": " + msg.what);                    wallStart = SystemClock.currentTimeMicro();                    threadStart = SystemClock.currentThreadTimeMicro();                }                //这里调用handler的分发消息的函数                msg.target.dispatchMessage(msg);                if (logging != null) {                    long wallTime = SystemClock.currentTimeMicro() - wallStart;                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);                    if (logging instanceof Profiler) {                        ((Profiler) logging).profile(msg, wallStart, wallTime,                                threadStart, threadTime);                    }                }                // 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(TAG, "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);                }                //回收消息,将消息的各成员变量置为空,释放内存                msg.recycle();            }        }    }

今天今天就写到这里,后续再更新,写的东西很浅,在下也是菜鸟一只。。。

0 0