Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列(Message Queue)和一个消息循环(Looper)。Android中除了UI线程(主线程),创建的工作线程默认是没有消息循环和消息队列的。如果想让该线程 具有消息队列和消息循环,并具有消息处理机制,就需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用 Looper.loop()进入消息循环。如以下代码所示:

classLooperThreadextendsThread{publicHandlermHandler;publicvoidrun(){Looper.prepare();mHandler=newHandler(){publicvoidhandleMessage(Messagemsg){//processincomingmessageshere}};Looper.loop();}}

这样该线程就具有了消息处理机制了。如果不调用Looper.prepare()来创建消息队列,会 报"java.lang.RuntimeException: Can't create handler insidethread that has not called Looper.prepare()"的错误。

通过下图可以清晰显示出UI Thread, Worker Thread, Handler, Massage Queue, Looper之间的关系:


解释上图中的几个基本概念:

1.Message

消息对象,顾名思义就是记录消息信息的类。这个类有几个比较重要的字段:

a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID。

b.obj:该字段是Object类型,我们可以让该字段传递某个多项到消息的接受者中。

c.what:这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理Button事件时,通过switch(v.getId())判断是点击了哪个按钮。

在使用Message时,我们可以通过new Message()创建一个Message实例,但是Android更推荐我们通过Message.obtain()或者 Handler.obtainMessage()获取Message对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的 Message实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的Message实例,则根据给定的参数new一个新Message对象。 通过分析源码可得知,Android系统默认情况下在消息池中实例化10个Message对象。

2.MessageQueue

消息队列,用来存放Message对象的数据结构,按照“先进先出”的原则存放消息。存放并非实际意义的保存,而是将Message对象以链表的方式串联 起来的。MessageQueue对象不需要我们自己创建,而是有Looper对象对其进行管理,一个线程最多只可以拥有一个MessageQueue。 我们可以通过Looper.myQueue()获取当前线程中的MessageQueue。

3.Looper

MessageQueue的管理者,在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象 和一个MessageQueue对象。倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通 过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象。在这个地方有一点需要注意,假如Looper对象位于应用 程序主线程中,则Looper.myLooper()和Looper.getMainLooper()获取的是同一个对象。

4.Handler

消息的处理者。通过Handler对象我们可以封装Message对象,然后通过sendMessage(msg)把Message对象添加到 MessageQueue中;当MessageQueue循环到该Message时,就会调用该Message对象对应的handler对象的 handleMessage()方法对其进行处理。由于是在handleMessage()方法中处理消息,因此我们应该编写一个类继承自 Handler,然后在handleMessage()处理我们需要的操作。

另外,我们知道,Android UI操作并不是线程安全的,所以无法在子线程中更新UI。但Andriod提供了几种方法,可以在子线程中通知UI线程更新界面:

  • Activity.runOnUiThread( Runnable )

  • View.post( Runnable )

  • View.postDelayed( Runnable, long )

  • Handler

比较常用的是通过Handler,用Handler来接收子线程发送的数据,并用此数据配合主线程更新UI。那么,只要在主线程中创建Handler对 象,在子线程中调用Handler的sendMessage方法,就会把消息放入主线程的消息队列,并且将会在Handler主线程中调用该 handler的handleMessage方法来处理消息。

packagecom.superonion;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Message;importandroid.util.Log;importandroid.os.Handler;publicclassMyHandlerextendsActivity{staticfinalStringTAG="Handler";Handlerh=newHandler(){publicvoidhandleMessage(Messagemsg){switch(msg.what){caseHANDLER_TEST:Log.d(TAG,"Thehandlerthreadid="+Thread.currentThread().getId()+"\n");break;}}};staticfinalintHANDLER_TEST=1;/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);Log.d(TAG,"Themainthreadid="+Thread.currentThread().getId()+"\n");newmyThread().start();setContentView(R.layout.main);}classmyThreadextendsThread{publicvoidrun(){Messagemsg=newMessage();msg.what=HANDLER_TEST;h.sendMessage(msg);Log.d(TAG,"Theworkerthreadid="+Thread.currentThread().getId()+"\n");}}}

以上代码中,Handler在主线程中创建后,子线程通过sendMessage()方法就可以将消息发送到主线程中,并在handleMessage()方法中处理

更多相关文章

  1. Android开发实践:使用Service还是Thread
  2. Android---44---使用AIDL Service 实现跨进程调用Service
  3. Android(安卓)Camera模块分析
  4. 深入浅出RxJava——在Android中使用响应式编程
  5. Android(安卓)性能优化方案大全
  6. Android资源管理框架(二)AssetManager创建过程
  7. Android主流三方库源码分析(七、深入理解ButterKnife源码)
  8. 从源码角度一步步分析AsyncTask的用法与原理
  9. Android的UI主线程是ActivityThread吗?

随机推荐

  1. SSM框架如何编写分页查询
  2. 最全面solrr入门教程
  3. 配置 nginx ssl 认证,并同时支持 http 80
  4. 如何在Eclipse中使用 Git详细步骤
  5. SSM框架做前后端分离项目
  6. IDEA快捷键总结大全
  7. HOW2J j2se实战小项目-记事本项目
  8. Servlet系列教材 (二)- 基础 - 如何获取浏
  9. Servlet系列教材 (一)- 基础 - 教程:开发第
  10. web前端开发仿天猫实战