您的位置:首页 > 其它

Handler消息机制分析

2016-05-16 23:50 281 查看

Handler消息机制分析

标签(空格分隔): Android Hander

概述

handler允许你发送和处理与MessageQueue消息队列有关的Message和Runnable对象

每个hanler实例与一个线程和该线程的队列相联系,它受限于该线程和该消息队列

handler有两种用法:

用于将来调度message和执行Runable对象

将一个不同线程的行为放入队列

调度信息方法:

post

postAtTime

postDelay

sendEmptyMessage

sendMessage

sendMessageAtTime

sendMessageDelayed

提醒:post方法允许你放入一个被MessageQueue消息队列调用的Runable对象

sendMessage方法允许将包含一包数据的Message对象放入队列。该Message消息将由Handler的HandlerMessage方法处理(当然你需要实现一个Handler的子类)

当使用post或者send方法的时候

1. 你可以允许他们立即执行(消息队列打算这个干的时候)

2. 指定一个时间延时(即Delay)

3. 指定一个绝对时间(即AtTime)

当一个进程为你的application应用创建的时候,它的主线程从事于运行一个消息队列,该消息队列关注管理顶级水平的一个应用对象(比如activitis,broadcast receiver等)和他们创建的窗口。你可以创建你自己的线程,然后在后台通过Handler与主应用线程交流(这些可以在你的线程中通过前面所说的post,sendMessage方法实现,给定的Message消息和Runnable对象会在handler的消息队列中调度并在适当的时候处理)。

消息处理机制(从发送消息到处理消息)

发送消息

从上可知发送消息主要有send和post方法,我们来看下

/*
将消息加入消息队列,放在所有消息后面
@param msg 参数
@uptimemillis 执行确切时间,精确到微妙(基于SystemClock时间)
@return true成功加入队列,false失败(通常是因为处理消息队列的looper推出了)

*/
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);//加入消息队列
}


一问:这里我们看见了mQuenue,这是何时创建呢?

我们可以在两个Hanler构造函数中看见

1. public Handler(Callback callback, boolean async) {
当FIND_POTENTIAL_LEAKS设置为真会检测extends 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());
}
}

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;
}
我们看见是由mLooper创建

2. public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;//一个接口,里面有一个抽象方法handleMessage(Message msg);
mAsynchronous = async;//设置handler是否进行异步处理
}
我们同样可以看见是由looper创建


二问:looper是什么何时创建消息队列

looper概述:

looper用于为一个线程运行消息循环,线程默认是没有与之相关的消息循环的。调用looper的prepare()可以在线程中创建一个消息循环来管理循环。looper的loop操作使之处理消息,知道loop终止。

一个常见的例子是:

class LooperThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();//初始化当前线程为一个looper

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};//完成了与looper的绑定。分析如下

Looper.loop();//运行当前线程的消息队列
}
}


注:

在主线程中运行的部分,都可以直接使用Handler,因为在主线程启动的过程中(ActivityThread的main函数里)会调用Looper.prepareMainLooper(),Looper类中也直接定义了一个static的looper实例sMainLooper用于存放主线程的Looper,可以通过静态方法获取到。 因此,凡是在主线程中运行的代码段里 都可以直接new Handler()而不用去绑定Looper,MessageQueue;

public static void main(String[] args) {
...

Looper.prepareMainLooper();//初始化当前线程作为一个Looper,并将之标记为应用的主Looper.

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}


looper与handler绑定过程

public Handler() {
this(null, false);
}
this会使用如下handler。可知looper通过Looper.myLooper在线程中完成绑定
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();//返回与当前线程关联的looper对象
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;
}


接下来如何在Looper中与线程绑定:

从上面可以知道,在prepare函数中初始化了一个线程为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));
}


sThreadLocal在Looper中的定义

// sThreadLocal.get() will return null unless you’ve called prepare().

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();


在此补充ThreadLocal概念:

1. ThreadLocal实现了一个Thread-local仓库,对于每一个线程都有自己的值。

2. 所有线程共享同样的ThreadLocal对象,但是每个线程访问时获取的是不同的值

3. 某个线程对ThreadLocal的变量的修改不会影响其他线程

4. 支持null值

回到正题:Looper是如何创建消息队列

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}


由此看出在Looper构造时已经创建

Handler消息如何执行

handler创建后发送的消息就会进入消息队列。此时如果没有为handler单独创建线程,则执行的是ActivityMain的Looper.loop(),否则执行当前线程的Looper.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();//重置当前线程IPC(进程间通信)的标识符

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();//将消息实例返回到全局池
}
}


可以看到是msg.target.dispatchMessage(msg)在处理消息

而在Message中定义有这样一个字段:

public final class Message implements Parcelable {
...
/*package*/ Handler target;
...
}


可知消息正是交给了Handler处理。

我们再看下发送消息过程

在上面sendMessageAtTime的我们可以看见函数enqueueMessage中 msg.target = this;

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//给target赋值为当前handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}


所以,消息由handler的dispatchMessage分配

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//判断msg的callback是否为空,不为空则调用handleCallback
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//判断mCallBack是否为空,不为空则调用其handleMessage
return;
}
}
handleMessage(msg);//由子类实现
}
}


如下,可以看见handleCallback只是调用callback(只是Runnable,一个赋值个Message的线程)


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


也就是说最后消息就传给了我们自定义的handleMessage;

呼!终于分析完了,不足之处请指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: