Hanlder异步消息自总结

由于在UI线程中不能做耗时长的操作,所以系统提供了Handler和AsyncTask来进行异步消息处理和任务;

异步消息处理机制Handler

Android中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue和Looper。

Message

Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

Handler

Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()或者post()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。

MessageQueue

MessageQueue是消息队列的意思,它主要是用于存放所有的Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只有一个MessageQueue对象。

Looper

Looper调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。

Handler源码分析:

Handler的构造函数

Handler的定义属性:

finalMessageQueuemQueue;

finalLoopermLooper;

finalCallbackmCallback;

finalbooleanmAsynchronous;

IMessengermMessenger;

在Handler中定义了7个构造函数,分别是:Handler()、Handler(Callback callback)、Handler(Looper

looper)、Handler(Looper looper, Callback callback)、Handler(boolean

async)、Handler(Callback callback, boolean async)、Handler(Looper

looper, Callback callback, boolean async);在上面我们已经说过Handler异步消息机制主要包含MessageQueue、Looper和Message三个部分,那么首先要分析的这三个属性怎么赋值;

构造方法一:

public Handler(Looper looper, Callback callback, boolean async) {

mLooper = looper;

mQueue = looper.mQueue;//在Looper中进行分析

mCallback = callback;

mAsynchronous = async;

}

构造方法二:

publicHandler(Callback callback, boolean async) {

if (FIND_POTENTIAL_LEAKS) {

final Class 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 handlerinside thread that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

下面看下我们在使用Handler是常用的空参构造函数的调用

public Handler() {

this(null, false);//调用Handler(Callback callback, booleanasync)

}

可以看到最终会在构造函数中进行对mLooper和mQueue的赋值;

Handler消息初始化

在Handler中对消息的初始化主要是重载了5个obtainMessage()方法;分别是

publicfinalMessageobtainMessage()

{

returnMessage.obtain(this);

}

publicfinalMessageobtainMessage(intwhat)

{

returnMessage.obtain(this, what);

}

publicfinalMessageobtainMessage(intwhat, Object obj)

{

returnMessage.obtain(this, what,obj);

}

publicfinalMessageobtainMessage(intwhat,intarg1,intarg2)

{

returnMessage.obtain(this, what,arg1, arg2);

}

publicfinalMessageobtainMessage(intwhat,intarg1,intarg2, Object obj)

{

returnMessage.obtain(this, what,arg1, arg2, obj);

}

可以看到在创建消息Message时会传进去一个参数this即当前Handler,这点很重要,我们知道在消息处理时要找到对应的处理消息的Handler;

Handler中的send方法

当handler在分线程进行完耗时的操作后并完成消息创建及配置,那么下面就进消息的发送;在handler中主要有:

空消息:

sendEmptyMessage(int what)

sendEmptyMessageDelayed(int what, long

delayMillis)

sendEmptyMessageAtTime(int what, long

uptimeMillis)

非空消息:

sendMessage(Message

msg)发送一个普通的消息。即延时为零的消息;’

sendMessageDelayed(Message

msg, long delayMillis)发送一个延时消息;

sendMessageAtFrontOfQueue(Message

msg);

sendMessageAtTime(Message

msg, long uptimeMillis);

上述方法最终会调用Handler中的enqueueMessage(MessageQueue

queue, Message msg, long uptimeMillis)方法,enqueueMessage()又会调用MessageQueue的enqueueMessage(msg,

uptimeMillis)方法,最终将消息send到消息队列中;

Handler中的Post方法

在Hanlder中处理定义了对消息的send方法之外,还定义了针对Runnable的post方法;相关方法:

post(Runnable r)调用方法sendMessageDelayed(getPostMessage(r),

0);

postAtTime(Runnable r, long uptimeMillis)调用sendMessageAtTime(getPostMessage(r),

uptimeMillis);

postAtTime(Runnable r, Object token, long

uptimeMillis) sendMessageAtTime(getPostMessage(r, token),

uptimeMillis);sendMessageAtTime(getPostMessage(r, token), uptimeMillis);

postDelayed(Runnable r, long delayMillis)调用sendMessageDelayed(getPostMessage(r),

delayMillis);

postAtFrontOfQueue(Runnable r)调用sendMessageAtFrontOfQueue(getPostMessage(r));

可以发现Handler的post方法最终是调用了相关send方法,但是所有的post方法同时调用的一个getPostMessage(r)来对消息的创建;实现如下

privatestaticMessagegetPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

returnm;

}

可以看到在该方法中主要是通过将Runnable复制给m.callback来实现;这将在对消息的分析是详细介绍;

Handler中的消息处理过程

我们知道,Handler消息机制中只要消息队列中存在消息,那么looper就不停的取出去消息并且将其交给Handler进行处理。这里我们暂时不关注looper是如何取出消息及分配消息,我们只关注消息是如何处理的;在Handler中对消息的处理只要一个方法:

publicvoiddispatchMessage(Message msg) {

if(msg.callback !=null) {

handleCallback(msg);

}else{

if(mCallback!=null){

if(mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

在该方法中首先要判断msg.callback !=null,而在上面我们已经分析过了只有在使用post相关的方法时msg.callback会被赋值;当msg.callback !=null时会调用handleCallback(msg):privatestaticvoidhandleCallback(Message message) {

message.callback.run();//即调用Runable的run方法

}

当msg.callback==null时首先要判断的时mCallback!=null;在这里说明一下什么是mCallback:在Handler中定义这样的一个final属性:final Callback mCallback,那么什么是Callback呢?

publicinterfaceCallback {

public boolean handleMessage(Messagemsg);

}

在Handler中定义这样一个接口,官方的定义是:

Callback interface you can use when

instantiating a Handler to avoid having to implement your own subclass of

Handler.

当mCallback!=null不为空时,如果public boolean handleMessage(Message

msg)方法返回的true,那么表示当前的message被处理,return;如果放回的丝false,那么在执行完public boolean handleMessage(Message

msg)方法后会继续执行handleMessage(msg)方法,完成对数据的处理;

Handler中的消息撤回和消息队列的判断

Handler中定义的消息撤回的方法:

removeMessages(int what)根据what来撤回消息;

removeMessages(int what, Object object)根据what和object来撤回消息;

removeCallbacksAndMessages(Object token)根据token撤回message和callbacks,当token是null是撤回消息队列的所有消息;

同时,handler中还定义了对消息队列进行查询的方法:

hasMessages(int what)

hasMessages(int what, Object object)

hasCallbacks(Runnable r)

Looper的实现

我们都知道handler的主要的任务就是进行线程间的通信,实现分线程和UI线程通信界面更新,但是我们发现在整个的handler中没有关于UI线程相关的东西;那么下面我们继续分析looper,希望能够找到着相关的东西;和Handler分析过程一样,我们首先看一下looper的构造函数和定义的属性:

Looper定义的相关的熟悉如下

staticfinalThreadLocalsThreadLocal=newThreadLocal();

privatestaticLoopersMainLooper;// guarded by Looper.class

finalMessageQueuemQueue;

finalThreadmThread;

然后查找Looper的构造函数,结果发现了:

privateLooper(booleanquitAllowed) {

mQueue=newMessageQueue(quitAllowed);//在消息队列中分析

mThread= Thread.currentThread();

}

私有的构造函数,有一种单例的感觉;接着却找到了这样一个方法prepare(),

publicstaticvoidprepare(){

prepare(true);

}

privatestaticvoidprepare(booleanquitAllowed) {

if(sThreadLocal.get() !=null) {

thrownewRuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(newLooper(quitAllowed));

}

可以new Looper的,接着分析,什么是sThreadLocal,找到ThreadLocal中的set和get方法,其中set()的作用是Sets the value of this variable for the

current thread,即将looper与sThreadLocal当前线程绑定;通过prepare克可以创建looper,同时Looper中还定义了myLooper()方法获取当前线程的looper;

publicstaticLoopermyLooper() {

returnsThreadLocal.get();

}

接下来就该从消息队列中获取消息了,即调用loop()方法;

publicstaticvoidloop() {

final Looper me = myLooper();

finalMessageQueue queue = me.mQueue;

…..

for(;;) {

Message msg = queue.next();// might block

if(msg ==null) {

// No message indicates that the

message queue is quitting.

return;

}

……

msg.target.dispatchMessage(msg);

……

}

}

主要是通过一个死循环不停的从消息队列中取出消息,然后执行msg.target.dispatchMessage(msg)方法即handler. dispatchMessage(msg)方法,由handler去完成消息的处理;

同时,除了消息的获取之外,Looper还定义了两个退出的方法quit()和quitSafely();这两个方法都调用了Messagequeue的quit()方法,,这两个方法的区别会在下面解析

Messagequeue时进行说明

publicvoidquit() {

mQueue.quit(false);

}

publicvoidquitSafely() {

mQueue.quit(true);

}

主线程Looper的问题,我们在UI使用Handler进行线程通信时没有手动的创建Loop而是由于主线的looper系统已经为我们创建好;

消息队列的实现

老规矩首先分析一下MessageQueue的构造函数,发现

// True if the message queue can be quit.

privatefinalbooleanmQuitAllowed;

MessageQueue(booleanquitAllowed) {

mQuitAllowed= quitAllowed;

mPtr=nativeInit();

}

结合MessageQueue和Looper的构造函数和prepare()方法,我们可以知道我们自己创建的MessageQueue都是可以quit,但是在Looper中还定义这么一个方法:

publicstaticvoidprepareMainLooper(){

prepare(false);//这个地方为false;

synchronized(Looper.class) {

if(sMainLooper!=null) {

thrownewIllegalStateException("The main Looper has already been prepared.");

}

sMainLooper=myLooper();

}

}

下面分析一下MessageQueue的enqueueMessage()方法和next();

booleanenqueueMessage(Message msg,longwhen) {

…….

msg.when = when;

Message p =mMessages;

booleanneedWake;

if(p ==null|| when == 0 || when

//

New head, wake up the event queue if blocked.

msg.next = p;

mMessages= msg;

needWake =mBlocked;

}

else

{

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;

}

if(needWake) {

nativeWake(mPtr);

}

}

returntrue;

}

消息队列消息的添加主要是进行相应的判断并且循环整个消息队列来进行按照时间的插入;

Message next() {

intpendingIdleHandlerCount = -1;// -1 only during

first iteration

intnextPollTimeoutMillis = 0;

for(;;) {

if(nextPollTimeoutMillis != 0) {

Binder.flushPendingCommands();

}

// We

can assume mPtr != 0 because the loop is obviously still running.

// The

looper will not call this method after the loop quits.

nativePollOnce(mPtr, nextPollTimeoutMillis);

synchronized(this) {

//Try to retrieve the next message.Returnif found.

finallongnow = SystemClock.uptimeMillis();

Message prevMsg =null;

Message msg =mMessages;

if(msg !=null&& msg.target ==null) {

//Stalled by a barrier.Find the nextasynchronous message in the queue.

do{

prevMsg = msg;

msg = msg.next;

}while(msg !=null&& !msg.isAsynchronous());

}

if(msg !=null) {

if(now < msg.when) {

nextPollTimeoutMillis =(int) Math.min(msg.when - now, Integer.MAX_VALUE);

}else{

// Got a message.

mBlocked=false;

if(prevMsg !=null){

prevMsg.next =msg.next;

}else{

mMessages= msg.next;

}

msg.next =null;

if(false)Log.v("MessageQueue","Returning message: "+ msg);

msg.markInUse();

returnmsg;

}

}else{

//

No more messages.

nextPollTimeoutMillis = -1;

}

//

Process the quit message now that all pending messages have been handled.

if(mQuitting) {

dispose();

returnnull;

}

if(pendingIdleHandlerCount < 0

&& (mMessages==null|| now

pendingIdleHandlerCount =mIdleHandlers.size();

}

if(pendingIdleHandlerCount <= 0) {

mBlocked=true;

continue;

}

if(mPendingIdleHandlers==null) {

mPendingIdleHandlers=newIdleHandler[Math.max(pendingIdleHandlerCount, 4)];

}

mPendingIdleHandlers=mIdleHandlers.toArray(mPendingIdleHandlers);

}

for(inti = 0; i

finalIdleHandleridler =mPendingIdleHandlers[i];

mPendingIdleHandlers[i]=null;//

release the reference to the handler

booleankeep =false;

try{

keep = idler.queueIdle();

}catch(Throwable t) {

Log.wtf("MessageQueue","IdleHandler threw exception", t);

}

if(!keep) {

synchronized(this) {

mIdleHandlers.remove(idler);

}

}

}

pendingIdleHandlerCount = 0;

nextPollTimeoutMillis = 0;

}

}

voidquit(booleansafe) {

if(!mQuitAllowed) {

thrownewRuntimeException("Main thread not allowed to quit.");

}//主线程不可退出

synchronized(this) {

if(mQuitting) {

return;

}

mQuitting=true;

if(safe) {

removeAllFutureMessagesLocked();//处理完所有的消息后提出

}else{

removeAllMessagesLocked();//直接退出,不再关注消息队列是否处理完

}

// We

can assume mPtr != 0 because mQuitting was previously false.

nativeWake(mPtr);

}

}

Message的实现

对于message的分析,主要是关注两点

Handlertarget;

Runnablecallback;

Message的创建主要是调用了其静态方法obtain():

* Return a newMessage instance from the global pool. Allows us to

avoidallocating new objects in many cases.

publicstaticMessageobtain() {

synchronized(sPoolSync) {

if(sPool!=null){

Message m =sPool;

sPool= m.next;

m.next=null;

sPoolSize--;

returnm;

}

}

returnnewMessage();

}

从整个Messge池中返回一个新的Message实例,在许多情况下使用它,因为它能避免分配新的对象

在上面我们已经知道在handler进行消息初始化的时候会调用obtain(Handler h)等方法其最终会通过obtain()进行消息返回并且对消息的target进行赋值;这也就是是在Loop()方法中进行消息分配的原因;Handler中的其他消息的初始化大家可以自己对应源码去看一下;

我们在Handler的分配的时候曾经有过这样一个判断

if(msg.callback !=null) {

handleCallback(msg);

}

下面我们看一下msg.callback,在消息初始化的时候,当我们传入一个Runnable时,

callback

Runnable that will execute when the message is handled.也就是说再消息发送出去后会在执行。

publicstaticMessageobtain(Handler h, Runnable callback) {

Message m =obtain();

m.target= h;

m.callback= callback;

returnm;

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容