您的位置:首页 > 运维架构

Looper、handler、message小结

2015-09-10 09:38 387 查看

Looper:

Looper.prepare();方法:为每个线程创建一个唯一的looper,并与当前线程联系起来。

Loop.prepare():这个方法只能调用一次,保证每个Thread只保存一个looper。

<span style="font-size:14px;">public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}  </span>


创建一个looper的时候会创建一个MessageQueue(消息队列):

<span style="font-size:14px;">private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread(); //与当前线程联系起来
}  </span>
Looper.loop();方法:不断的获取MessageQueue的message,并通过message.taget.dispatchmessage(msg) 将消息发送出去。

<span style="font-size:14px;">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.recycle();
}
}  </span>


Hander:是如何与message联系起来的?

<span style="font-size:14px;">public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
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());
}
}

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;
}  </span>
<span style="font-size:14px;">
</span>
<span style="font-size:14px;">mLooper = Looper.myLooper();  通过这个获取了线程保存的looper.
mQueue = mLooper.mQueue; 通过这个将线程保存的looper的messagequeue与hanger的mqueue联系起来。
handler发送消息:
</span>
<span style="font-size:14px;">
</span>
<span style="font-size:14px;"></span><pre name="code" class="java"> public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}





<span style="font-size:14px;">   public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}</span>


<span style="font-size:14px;"> public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}</span>


<span style="font-size:14px;"> 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);
}</span>


<span style="font-size:14px;"> private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}</span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;">
</span></span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;">通过msg.target = this; 将message的target指向了handler,然后再将message压入messagequeue中,这样在loop方法中的时候获取到message后通过message.taget.dispatchmessage(msg) 就可以将消息发送到handler中处理。
handler是怎么接收到message的:
message通过message.taget.dispatchmessage(msg) ,handler的dispatchMessage()方法如下:通过handlerMessage将消息发送处理。
</span></span><pre name="code" class="java">public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}



<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;">
这里对消息的处理除了handlerMessage(),还有一个mCallback.handleMessage(msg),还有的是msg.callback:
</span></span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;">
</span></span>
所以handler处理消息的方法有三种,常用以下两种:

<span style="font-size:14px;"> Handler dHandler=new Handler(new Handler.Callback() {

@Override
public boolean handleMessage(Message arg0) {

return false;
}
});</span>


<span style="font-size:14px;">mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {

}
};</span>


总结:

1:主线程的时候实例化handler时已经在ui主线程添加了looper,所以不用添加looper,而非主线程的时候实例化handler时必须添加looper,否则会报错误;throw new RuntimeException("No Looper; Looper.prepare() wasn't called
on this thread.");


new Thread()

{

private Handler handler;

public void run()

{

Looper.prepare();

handler = new Handler()

{

public void handleMessage(android.os.Message msg)

{

};

};

Looper.loop();

}

2.整个过程:通过Looper.prepare();给当前线程保存一个唯一的Looper对象,该looper对象创建了一个Message队列。然后handler实例化时获取到当前线程的looper对象,并拿到该looper对象的消息队列。handler调用 sendMessage()方法过程中调用到enqueueMessage()方法,并将要发送的message的target指向当前的发送消息的handler,同时将消息压入要发送消息的handler的消息队列(也就是当前线程looper的消息队列,因为它于handler已经挂钩了),最后looper.loop();该方法不断获取到消息队列的Message,并通过message.taget.dispatchmessage(msg)将消息发送出去。handler可以通过handlerMessage()也可以通过Handler.Callback()获取到发送过来的Message,然后处理。

looper作用:创建当前线程的looper对象,该对象包含了一个消息队列,然后不断的获取消息队列的消息发送出去。

handler作用:获取到当前线程的looper的消息队列,发送消息时将消息的target(相当于要发送的地址)指定,并将消息压入消息队列中。


Handler发送消息有主要有两种,post系列、send系列:

post系列:

public final boolean
post(Runnable r):


Causes the Runnable r to be
added to the message queue. The runnable will be run on the thread to which this handler is attached.

postAtTime(Runnable
r, long uptimeMillis)


Causes the Runnable r to be added to the message queue, to be run at a specific time given by uptimeMillis

postDelayed(Runnable r, long delayMillis)

Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses

send系列主要是发送message。

post可以设置发送时间,可以延迟发送,除了handler之外,View也有post的方法:

<span style="font-size:14px;">imageView.post(new Runnable() {
@Override
public void run() {
mAnimation.start();

}
});</span>


所以对一些view的ui操作可以通过post更新,其原理是:

View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: