读书人

android线程有关1

发布时间: 2012-06-27 14:20:09 作者: rapoo

android线程相关1

?

android中的Handler对于这部分的内容,将分成4 小节来描述:1)职责与关系2)消息循环3)线程与更新4)几点小结----------------------------------------------------------1) 接下来,我们开始这部分的内容,首先了解一下各自的职责及相互之间的关系。职责Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue 统一列队,终由 ??????????????Handler 处理。Handler:处理者,负责Message 的发送及处理。使用Handler 时,需要实现handleMessage(Message msg) ?????方法来对特定的Message 进行处理,例如更新UI 等。MessageQueue:消息队列,用来存放Handler 发送过来的消息,并按照FIFO 规则执行。当然,存放Message ?????并非实际意义的保存,而是将Message 以链表的方式串联起来的,等待Looper 的抽取。Looper:消息泵,不断地从MessageQueue 中抽取Message 执行。因此,一个MessageQueue 需要一Looper。Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
关系????class Class Model????Looper MessageQueue????HandlerHandler,Looper 和MessageQueue 就是简单的三角关系。Looper 和MessageQueue 一一对应,创建一个Looper 的同时,会创建一个MessageQueue。而Handler 与它们的关系,只是简单的聚集关系,即Handler 里会引用当前线程里的特定Looper 和MessageQueue。这样说来,多个Handler 都可以共享同一Looper 和MessageQueue 了。当然,这些Handler 也就运行在同一个线程里。
2) 接下来,我们简单地看一下消息的循环过程:生成Message msg = mHandler.obtainMessage();msg.what = what;msg.sendToTarget();
发送MessageQueue queue = mQueue;if (queue != null) {msg.target = this;sent = queue.enqueueMessage(msg, uptimeMillis);}在Handler.java 的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message 的target 设定成自己(目的是为了在处理消息环节,Message 能找到正确的Handler),再将这个Message 纳入到消息队列中。
抽取Looper me = myLooper();MessageQueue queue = me.mQueue;while (true) {Message msg = queue.next(); // might blockif (msg != null) {if (msg.target == null) {// No target is a magic identifier for the quit message.return;}msg.target.dispatchMessage(msg);msg.recycle();}}在Looper.java 的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue 中获取下一个(next 方法)Message,然后通过Message 中携带的target 信息,交由正确的Handler 处理(dispatchMessage 方法)。
处理if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}在Handler.java 的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。至于dispatchMessage 方法中的另外一个分支,我将会在后面的内容中说明。至此,我们看到,一个Message 经由Handler 的发送,MessageQueue 的入队,Looper的抽取,又再一次地回到Handler 的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。
3)剩下的部分,我们将讨论一下Handler 所处的线程及更新UI 的方式。在主线程(UI 线程)里,如果创建Handler 时不传入Looper 对象,那么将直接使用主线程(UI 线程)的Looper 对象(系统已经帮我们创建了);在其它线程里,如果创建Handler 时不传入Looper 对象,那么,这个Handler 将不能接收处理消息。在这种情况下,通用的作法是:class LooperThread extends Thread {public Handler mHandler;public void run() {Looper.prepare();mHandler = new Handler() {public void handleMessage(Message msg) {// process incoming messages here}};Looper.loop();}}在创建Handler 之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper 跑起来(Looper.loop),抽取Message,这样,Handler 才能正常工作。因此,Handler 处理消息总是在创建Handler 的线程里运行。而我们的消息处理中,不乏更新UI 的操作,不正确的线程直接更新UI 将引发异常。因此,需要时刻关心Handler 在哪个线程里创建的。
如何更新UI 才能不出异常呢?SDK 告诉我们,有以下4 种方式可以从其它线程访问UI线程: Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long) Handler其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View 获得当前线程(即UI 线程)的Handler,然后将action 对象post 到Handler 里。在Handler 里,它将传递过来的action 对象包装成一个Message(Message 的callback为action),然后将其投入UI 线程的消息循环中。在Handler 再次处理该Message 时,有一条分支(未解释的那条)就是为它所设,直接调用runnable 的run 方法。而此时,已经路由到UI 线程里,因此,我们可以毫无顾虑的来更新UI。
4)?几点小结 Handler 的处理过程运行在创建Handler 的线程里 一个Looper 对应一个MessageQueue 一个线程对应一个Looper 一个Looper 可以对应多个Handler 不确定当前线程时,更新UI 时尽量调用post 方法

读书人网 >Android

热点推荐