当前位置: 代码迷 >> 移动开发 >>

如果上面关于回调的内容讲的还算明白,请列位接着看这四个好基友的故事。

  详细解决方案

如果上面关于回调的内容讲的还算明白,请列位接着看这四个好基友的故事。

热度:7882   发布时间:2013-02-26 00:00:00.0
关于Handler二三事(上)

 一直以来,Handler于我而言都是难以形容的大麻烦。姑且不论线程通信一二三,就算是如何利用Handler来实现各项业务间消息传输,我也只能粗浅的说说如何跟踪消息而已。

跟它较劲了很久,零零碎碎总结了不少,总算是明白了些。记录下来权当作经验与各位分享。

 

我理解的Handler回调

In computer programming, a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at someconvenient time. The invocation may be immediate as in a synchronous callback or it might happen at later time, asin an asynchronous callback.

我不知道诸位对它的解释是否满意,反正对我来说,说了跟没说一样。我理解回调的意义,知道回调的目的……但是,我不知道android Activity代码中一串串的onXXXX究竟是怎么来的!

这也许就是跨行从业的悲剧,一直学嵌入式硬件的我拼命阅读理解该死的底层代码,内核函数,仍然无法弄明白这个回调究竟是怎么起作用的,甚至怎么用都不明白。

直到有一天,我看到了这段话:

As your activity enters the paused state, thesystem calls theonPause() method on your Activity, which allows you to stopongoing actions that should not continue while paused (such as a video) orpersist any information that should be permanently saved in case the usercontinues to leave your app.

我终于有了那么点开窍,回调机制不就是披着软件马甲的硬件中断吗?

不知道在座各位是否了解嵌入式硬件中断,不过我知道做过单片机、dsp的同学肯定明白。所谓的中断,简单地讲就是当相应的中断源产生中断后,CPU会做现场保护,然后把PC指针跳进事先写好的中断服务程序中执行中断服务内容,执行完后CPU再恢复现场,接着该干嘛干嘛。

我这么说各位是否能看出来,这货活脱脱就是回调啊(当然肯定有不同的地方,但LZ就是这么理解的)!某个事件源引起了系统响应,进而调用相应的回调函数来实现该事件源的处理内容,从而完成了“事件响应”的处理。


我可以不去管系统是如何产生和触发相应的事件源的,虽然在设计硬件时我需要区分中断是硬中断还是软中断,中断向量表是怎么写的,等等等等。但是这里我可以不管你,我只需要知道硬件层面有相应的事件源消息产生了。

我在意的是,什么样的事件源与什么样的回调函数挂钩。简单地说,我需要知道什么事件源导致回调onCreate方法,什么事件源导致回调onClick方法。

相应的,我的工作,简单的说就是编写对应事件源下的中断服务程序(回调函数)了。我知道按下Activity上的一个虚拟Button,系统应该进行某些动作(譬如弹出个菜单,拨出个电话等),那么我只需要详细的描述onClick这个回调就可以了(当然,还有一些其他的配置代码需要另行编写)。

这个理解也许还不是那么恰当,但对目前的我来说,确实清楚了android代码架构和过去过程式编码的一些区别——android代码恐怕把很多设计底层的内容都隐藏了,暴露给程序员的,更多的是一些工具方法,其实从某种意义上说,所谓的编程倒像是在原有框架上一点点补足具体实现的内容。

而我之前难以理解的,其实是回调的实现机制而不是回调实现的具体内容了。


Thread、Handler、Looper以及Message

前文书说了,我一直维护framework侧代码,Activity什么的写的真心不多。那么在framework侧为什么会说到回调呢?

这是因为万恶的HandleMessage随处都在啊!

   /**    * When overridden the derived class needs to call    * super.handleMessage(msg) so this method has a    * a chance to process the message.    *    * @param msg    */   @Override   public void handleMessage(Message msg) {       AsyncResult ar;…}

老大说“……喏,记得把这几个消息回调实现了,然后看一下log成功没有”

我:“#¥%@……”

 

要说这四个好基友的关系,就需要理顺他们之间混乱的关系。

先把结论抛出来,我再慢慢的细说内容吧:

所谓的Handle-Message机制,与其说是某种复杂的消息处理机制,不如把它看成送快递的。打了收件人(target)标记的快递(message)被扔到一台不停旋转的传送带(Looper)上,系统每取出一个快递,就根据上面标签的内容把它发配到对应的收件人那去,收件人再根据标签上标注的签名(what)来分别处理不同的快递。

 

好了,接下来我讲讲我的心得,说的不对的地方请各位指正。


小误会引发的大问题

在理解Handle-Message机制的过程中,虽然整体的流程和概念我可以很快弄明白,但有个细节一直纠缠着我,如鲠在喉。

就是这个obtainMessage方法。

先来看一下,obtain的英文解释:

       obtain[][?b?tein] [][?b?tein] 

       vt.获得,得到;流行;买到,达到(目的)

       vi.通行,通用;流行;存在

 

可以见得,这个obtainMessage方法,应该指的是获取相应消息的意思,联系到它的定义:

   public final Message obtainMessage(int what)    {       return Message.obtain(this, what);}

我理所当然的认定这个方法指的是处理事件线程获取目标消息的意思……

因此,之后我的理解统统走了样,通过obtianMessage方法Handler线程得到了对应的消息,那么接下来就应该交给自己handleMessage来处理,可是这个SendMessage方法是什么!谁能告诉我为什么会有 sendMessageDelayed(obtainMessage(EVENT_CALL_RING_CONTINUE,token, 0), mCallRingDelay);这种情况。

把自己辛辛苦苦搜集到的消息再发出去算是怎么回事!?

我彻底混乱了。

 

所以,尽管看了不少的解析消息机制的文章,我还是非常痛苦的理解这个该死的Handle-Message到底是什么意思。

直到读完Message.java代码,我才发现所谓的obtian并不是从“消息源”中获取消息,而是从“消息池”中获取消息啊!所谓的obtianMessage过程,与其理解为获取消息,不如理解为“产生”消息更合适吧。

 

整个的流程应该是这么个顺序才对:

  • 线程A从消息池中挖出一个消息,把自己的戳子,处理对象说明,附加内容等等都加上去,形成一个有实际意义的消息。
  • 通过SendMessage方法,把这个消息加入目标线程的消息队列MessageQueue中去。
  • 这个消息队列由目标线程的Looper维护,Looper会通过loop方法轮询队列中的消息,轮询到这个消息的时候,根据该消息中指向的target目标,调用对应Handler对象的dispatchMessage()方法把它分发给相应的处理方法。虽然通常来说,这个处理方法就是重写后的handleMessage()方法。

这个过程,宏观上看来,就是线程A抛出了一个消息,由自己或者是线程B在适当的时刻进行异步处理,这个处理内容就是handleMessage的回调函数。


把大象塞到冰箱里

原谅我用这个稍显夸张的副标题,不过它确实是我第一次理解Handler类时的真实感想。

为什么叫把大象塞到冰箱里?

原话是这么说的,请问把大象塞到冰箱里要几步?

这个Handler.java给我的感觉就是如此,使用Handler,可以不用纠结到把大象塞到冰箱里究竟应该怎么使劲,只需要知道“开门,塞进去,关门”就ok了。

为什么这么说?

你看我们平时都是怎么做的,上层注册一个消息,然后在对应线程中new一个Handler对象,在Handler对象里重写handleMessage方法处理消息的回调就ok了。细节什么的统统不用管啊……

 

而真实的情况是什么呢,我想有些就如我上小结所写的,有些我还没理解。它应该是线程调度跟消息共享共同作用的结果。而底层封装的太过于漂亮,以至于上面运用它的人只需要开关冰箱门就搞定了消息的回调过程……真是惬意啊。

但是对于androider来说,光会开关冰箱门还是远远不够的,得深入了解才行。对于Handler我仍有很多的疑问,譬如为啥sendMessage()方法中指定的msg.target为this,而不让形参直接传一个进来,这样不是更方便吗?

总之,handler是个非常值得学习的内容,搞定了这个,我才能继续说说真正跟呼叫业务相关的消息触发内容。


1楼lixinnan18昨天 14:35
handler 一个线程处理帮助类
  相关解决方案