您的位置:首页 > 移动开发 > Android开发

Android异步消息处理机制Handler

2016-08-10 23:53 399 查看
很多人第一次接触Handler可能是因为一句话”子线程不能操作ui”,那子线程能不能操作ui呢?我们在这里不多讨论(其实是可以的,但是线程不安全),我们来分析下handler是如何运转起来的。

一般用法都是在“主线程”中new一个handler

Handler mhandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}


然后在子线程中sendMessage

Message msg= Message.obtain();
msg.what = FLAG;
msg.obj = obj;
mhandler.sendMessage(msg);


我画了一张图简单得阐述了中间过程,可以先看一下



很显然上面得两段代码就分别是左边进去和右边出来部分,从图中野可以看出,我们接下来就应该去看下Looper这个类了。其中 prepare()和loop()是我们注意到的。

我们来看下prepare()

/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
//在当前线程new了一个Looper对象
}


注释说:初始化当前线程作为一个looper。

这给了你一个机会来创建handler,在调用loop()前你必须先prepare(),而我们一般使用都没有先prepare(),所以为啥一开始我说在主线程new一个handler,因为在ActivityThread中已经帮我们建立好了一个looper(注意*内容*)

public static final void main(String[] args) {
SamplingProfilerIntegration.start();

Process.setArgV0("<pre-initialized>");

**Looper.prepareMainLooper();**

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

**Looper.loop();**

if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}

thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}


看完prepare()我们来看下loop()

/**
* 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();
}
}


其中第一行,我们可以看到

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;


确认当前线程中是否有looper对象,如果有的话获取到当前MessageQueue的对象mQueue,其中mQueue在Looper的构造方法中就已经new好了

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


接下来我们看到了一个死循环

for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}


queue不断的在读取下一个消息,如果下一个消息为空则做延时操作,如果接收到消息那么调用msg.target.dispatchMessage(msg)方法将消息发送出去(msg.target这个属性我们先看为mhandler,等下提到)

,那发送到哪里了呢?上面说到dispatchMessage()是handler的方法,我们到Handler中看看

/**
* 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);
}
}


是的找到他了,他又调用了handleMessage();这个方法,那我们来看下他的实现把

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


空实现!!!是的这就到了我们编写的部分,我们new了handler之后要重写handleMessage方法,详见文章顶部第一段代码,到这里我们说完了Looper从preapre()到loop()再到handleMssage(),那msg是怎么从子线程发送到“主线程”的mhandler手里呢??

那我们就要来看下sendMessag()这个方法了

public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}


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);
}


我们发现这几个方法到后面都是调用了sendMessageAtTime()这个方法,并却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);
}


是的,你发现了,在这里 msg.target = this;他将当前handler的对象赋值给了msg的target属性,这也就是为什么前面说将msg.target看作是handler,而MessageQueue的enqueueMessage方法就是将msg放置到队列当中去!

那msg是怎么从子线程发送到“主线程”的mhandler手里呢??

我们来看下handler的构造方法

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;
}


其中

mLooper = Looper.myLooper();//确保了子线程中的Looper对象来源于"主线程"


并且

mQueue = mLooper.mQueue;//确保了sendMessage()发送出去的msg是发送到主线程Looper的消息队列


到此为止一个常用handler的使用处理流程就说完了!也许有理解错的地方还望大家指正!

参考博文: Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

Android Handler机制

我的博客网站:http://huyuxin.top/欢迎大家访问!评论!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐