Android之Handler机制

来源:互联网 发布:女大十八变知乎 编辑:程序博客网 时间:2024/06/03 10:04
在了解Handler机制之前,先要明白几个单词的意思:
Handler:操作者Message:消息MessageQueue:消息队列Looper:做环的人Loop:环prepare:准备


这些词都是我们在子线程跟UI线程通讯是经常用到的类或者方法,下面分析开发中比较常用的简单的线程间通讯以及它们之间的关系

具体代码如下:

第一种:

public class mThead extends Thread{@Overridepublic void run() {Message msg=Message.obtain();msg.what=0;mHandler.sendMessage(msg);super.run();}}public Handler mHandler=new Handler(){public void handleMessage(Message msg) {if(msg.what==0){Toast.makeText(MainActivity.this, "通讯成功", Toast.LENGTH_SHORT).show();}};};

第二种:

public class hThread extends Thread{@Overridepublic void run() {Looper.prepare();Toast.makeText(MainActivity.this, "通讯成功", Toast.LENGTH_SHORT).show();Looper.loop();super.run();}}


 

第一种通讯分析:子线程mThead通过handler作为传输纽带,把Toast的信息加入消息队列MessageQueue,就好像是纽带传输货物一样,把子线程mThead作为动力,handler作为纽带,message作为货物,MessageQueue作为货物仓库,Looper对象作为仓管部门,UI线程作为老板,message被handler依靠mThread动力运输到仓库MessageQueue(入队消息到消息队列中的所有挂起的消息)后,仓管员通过Looper.prepare()给UI线程(老板)打电话,提示有货物待处理,UI线程就会要求looper对象循环取出MessageQueue里面的message(消息),直到循环结束,然后UI线程进行处理。

第二种通讯分析:就是Looper.prepare()把Toast信息加入MessageQueue,再通过Looper.loop()循环取出,交给UI线程处理,当MessageQueue队列中没有了message,循环就结束。

经过大体的分析Thread和UI线程通过handler通讯,下面将具体分析这些进程的详细流程

首先看看Handler对象调用的方法

 

public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }public final boolean sendEmptyMessage(int what)    {        return sendEmptyMessageDelayed(what, 0);    } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {        Message msg = Message.obtain();        msg.what = what;        return sendMessageDelayed(msg, delayMillis);    }public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        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);    }


从上述代码中可以看出,Handler把Message加入MessageQueue队列中经过了sendMessageDelayed→sendMessageAtTime→enqueueMessage方法,重点在于enqueueMessage的方法上,从代码可以看出msg.target = this,把msg的target属性赋值为当前的handler对象,就是把handler发送的信息,加入消息队列中,然后再给Looper.loop()方法取出消息。

下面来看Looper主要代码

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));    }    public static void loop() {        final Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final 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();        for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            // This must be in a local variable, in case a UI event sets the logger            final Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            final long traceTag = me.mTraceTag;            if (traceTag != 0) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            try {                msg.target.dispatchMessage(msg);            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            if (logging != null) {                logging.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(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.recycleUnchecked();        }    }    /**     * Return the Looper object associated with the current thread.  Returns     * null if the calling thread is not associated with a Looper.     */    public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }
private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

当Handler发送的信息加入了消息队列,也就是MessageQueue,就需要有人通知UI线程并且从队列中把信息取出来;从上述代码中可以看出,Looper.prepare()方法把方法体加入消息队列,然后loop方法通过循环把MessageQueue里面的消息一个个取出来。

目前对于api分析就那么多,有需要最好自己去研究Handler、Message、Looper、MessageQueue的源码。

希望能帮到大家去更好的理解handler和线程通讯

不足之处,请留言指出,谢谢!



 

3 0
原创粉丝点击