Android Handler

来源:互联网 发布:威纶触摸屏数据导出 编辑:程序博客网 时间:2024/06/16 20:33

一点点更新吧


Handler


在android中,每个thread有一个messageQueue,handler负责deliver message和execute message


deliver message的方法又sendMessage, sendMessageDelayed, sendMessageAtTime,sendMessageAtFrontOfQueue,但最终都会调用handler.enqueue方法,如下源码:



private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}

可以看到,在这里,message的target被设为当前的handler,后边在Looper.loop方法中会看到msg.target.dispatchMessage(msg)的调用,此处的target就是handler实例。


第2,3行是设置message是否是asynchronous异步的。

最后一行是调用MessageQueue.enqueueMessage(msg,uptimeMillis)

下面是MessageQueue.enqueueMessage的源码:

boolean enqueueMessage(Message msg, long when) {
//每个message必须有一个target,即handler    if (msg.target == null) {        throw new IllegalArgumentException("Message must have a target.");    }
//message正在被使用    if (msg.isInUse()) {        throw new IllegalStateException(msg + " This message is already in use.");    }    synchronized (this) {
//messageQueue执行了quit,不再进行消息处理        if (mQuitting) {            IllegalStateException e = new IllegalStateException(                    msg.target + " sending message to a Handler on a dead thread");            Log.w("MessageQueue", e.getMessage(), e);
//message重置,以便再利用,Message.Obtain()            msg.recycle();            return false;        }
        msg.markInUse();        msg.when = when;        Message p = mMessages;        boolean needWake;
//将message压入queue        if (p == null || when == 0 || when < p.when) {            // New head, wake up the event queue if blocked.            msg.next = p;            mMessages = msg;            needWake = mBlocked;        } else {            // Inserted within the middle of the queue.  Usually we don't have to wake            // up the event queue unless there is a barrier at the head of the queue            // and the message is the earliest asynchronous message in the queue.            needWake = mBlocked && p.target == null && msg.isAsynchronous();            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);        }    }    return true;}

上面简述了handler.enqueque()的方法,下面是说说handler.dispatchMessage()方法:


/** * Handle system messages here. */public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

代码很简单直观:

1. 如果message有callback,则调用handleCallback(msg),进而调用message.callback.run(),这需要创建message时写好callback方法。如下:

private static void handleCallback(Message message) {    message.callback.run();}

2. 如果message没有callback,

2.1. 但是handler的mCallback参数不为空,则调用mCallback.handleMessage()。Callback是接口,需要重写handleMessage方法,如下:

public interface Callback {    public boolean handleMessage(Message msg);}

2.2 handler的mCallback参数为空,调用handler的handleMessage方法,该需要重写:

/** * Subclasses must implement this to receive messages. */public void handleMessage(Message msg) {}

所以我们初始化handler的时候可以使用两种方法(实际有很多种,只举两种我常用的例子),注意两个handleMessage方法的返回值类型不同,一个boolean一个void:

Handler mHandler = new Hander(new Callback(){

@Override

public bolean handleMessage(Message msg){

//TODO

}

})


Handler mHandler = new Handler(){

@Override

public void handleMessage(Message msg){

//TODO

}

}


Looper

提到handler必不可少的要说Looper。Looper,顾名思义,就是用来做循环的,它可以对MessageQueue进行循环(loop()方法)。每个Thread都要有一个Looper,否则无法接收Message。


Looper有几个重要的方法:

prepare(),loop(),quit()。

prepare(),初始化,必须要做,且只能执行月hi次

/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */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        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);        }        // 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();    }}


原创粉丝点击