- 浏览: 42709 次
文章分类
最新评论
Android
消息机制
在 Android 开发中,有时会需要进行一个耗时的操作,例如:联网从远程读取数据,或者读取本地较大的一个文件的时候,这样的操作会引起系统长时间的等待,这时用户不能操作其它动作。长时间的等待给人假死的感觉,用户体验不好。究其原因,因为这样的操作都是在一个线程中完成。解决的办法可以采用类似 AJAX 的异步操作,把这类耗时的操作都放在另一个线程中处理。
线程内部或者线程之间需要进行信息的交互,那这个交互如何来实现的呢, Android 为我们提供了以下几个类进行线程间的信息交互。
1.Message
消息对象,顾名思义就是记录消息信息的载体类。这个类有几个比较重要的字段:
- arg1 和 arg2 :我们可以使用两个字段用来存放我们需要传递的整型值,在 Service 中,我们可以用来存放 Service 的 ID 。
- obj :该字段是 Object 类型,我们可以让该字段传递某个多项到消息的接受者中。
- 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 对象。
在 Android 系统中,除了主线程有默认的 Looper 对象,其它线程默认是没有 Looper 对 象。如果想让我们新创建的线程拥有 Looper 对象时,我们首先需要调用 Looper.prepare() 来给线程创建一个消息循环,然后调用 Looper.loop() 来使消息循环起作用,从消息队列里取消息,处理消息。典型的用法如下:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); //其它需要处理的操作 Looper.loop(); } }
4.Handler
消息的处理者。通过 Handler 对象我们可以封装 Message 对象,然后通过 sendMessage(msg) 把 Message 对象添加到 MessageQueue 中;当 MessageQueue 循环到该 Message 时,就会调用该 Message 对象对应的 handler 对象的 handleMessage() 方法对其进行处理。由于是在 handleMessage() 方法中处理消息,因此我们应该编写一个类继承自 Handler ,然后在 handleMessage() 处理我们需要的操作。
/** * * @author coolszy * @blog http://blog.csdn.net/coolszy * */ public class MessageService extends Service { private static final String TAG = "MessageService"; private static final int KUKA = 0; private Looper looper; private ServiceHandler handler; /** * 由于处理消息是在Handler的handleMessage()方法中,因此我们需要自己编写类 * 继承自Handler类,然后在handleMessage()中编写我们所需要的功能代码 * @author coolszy * */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // 根据what字段判断是哪个消息 switch (msg.what) { case KUKA: //获取msg的obj字段。我们可在此编写我们所需要的功能代码 Log.i(TAG, "The obj field of msg:" + msg.obj); break; // other cases default: break; } // 如果我们Service已完成任务,则停止Service stopSelf(msg.arg1); } } @Override public void onCreate() { Log.i(TAG, "MessageService-->onCreate()"); // 默认情况下Service是运行在主线程中,而服务一般又十分耗费时间,如果 // 放在主线程中,将会影响程序与用户的交互,因此把Service // 放在一个单独的线程中执行 HandlerThread thread = new HandlerThread("MessageDemoThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // 获取当前线程中的looper对象 looper = thread.getLooper(); //创建Handler对象,把looper传递过来使得handler、 //looper和messageQueue三者建立联系 handler = new ServiceHandler(looper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "MessageService-->onStartCommand()"); //从消息池中获取一个Message实例 Message msg = handler.obtainMessage(); // arg1保存线程的ID,在handleMessage()方法中 // 我们可以通过stopSelf(startId)方法,停止服务 msg.arg1 = startId; // msg的标志 msg.what = KUKA; // 在这里我创建一个date对象,赋值给obj字段 // 在实际中我们可以通过obj传递我们需要处理的对象 Date date = new Date(); msg.obj = date; // 把msg添加到MessageQueue中 handler.sendMessage(msg); return START_STICKY; } @Override public void onDestroy() { Log.i(TAG, "MessageService-->onDestroy()"); } @Override public IBinder onBind(Intent intent) { return null; } }
注 :在测试代码中我们使用了 HandlerThread 类,该类是 Thread 的子类,该类运行时将会创建 looper 对象,使用该类省去了我们自己编写 Thread 子类并且创建 Looper 的麻烦。
下面我们分析下程序的运行过程:
1.onCreate()
首先启动服务时将会调用onCreate()方法,在该方法中我们new了一个HandlerThread对象,提供了线程的名字和优先级。
紧接着我们调用了start()方法,执行该方法将会调用HandlerThread对象的run()方法:
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
在run()方法中,系统给线程添加的Looper,同时调用了Looper的loop()方法:
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } }
通过源码我们可以看到loop()方法是个死循环,将会不停的从MessageQueue对象中获取Message对象,如果MessageQueue 对象中不存在Message对象,则结束本次循环,然后继续循环;如果存在Message对象,则执行 msg.target.dispatchMessage(msg),但是这个msg的.target字段的值是什么呢?我们先暂时停止跟踪源码,返回到 onCreate()方法中。线程执行完start()方法后,我们可以获取线程的Looper对象,然后new一个ServiceHandler对象, 我们把Looper对象传到ServiceHandler构造函数中将使handler、looper和messageQueue三者建立联系。
2.onStartCommand()
执行完onStart()方法后,将执行onStartCommand()方法。首先我们从消息池中获取一个Message实例,然后给 Message对象的arg1、what、obj三个字段赋值。紧接着调用sendMessage(msg)方法,我们跟踪源代码,该方法将会调用 sendMessageDelayed(msg, 0)方法,而sendMessageDelayed()方法又会调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)方法,在该方法中我们要注意该句代码msg.target = this,msg的target指向了this,而this就是ServiceHandler对象,因此msg的target字段指向了 ServiceHandler对象,同时该方法又调用MessageQueue 的enqueueMessage(msg, uptimeMillis)方法:
final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { pprev = p; pp = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
该方法主要的任务就是把Message对象的添加到MessageQueue中(数据结构最基础的东西,自己画图理解下)。
handler.sendMessage()-->handler.sendMessageDelayed()-->handler.sendMessageAtTime()-->msg.target = this;queue.enqueueMessage==>把msg添加到消息队列中
3.handleMessage(msg)
onStartCommand()执行完毕后我们的Service中的方法就执行完毕了,那么handleMessage()是怎么调用的呢?在前 面分析的loop()方法中,我们当时不知道msg的target字段代码什么,通过上面分析现在我们知道它代表ServiceHandler对 象,msg.target.dispatchMessage(msg);则表示执行ServiceHandler对象中的 dispatchMessage()方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
该方法首先判断callback是否为空,我们跟踪的过程中未见给其赋值,因此callback字段为空,所以最终将会执行handleMessage()方法,也就是我们ServiceHandler类中复写的方法。在该方法将根据what字段的值判断执行哪段代码。至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱中。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。
总结:
1.消息相关类关系图示和建立过程:
1).在线程B中,需要建立Looper和MessageQueue的消息循环机制。通过Looper.prepare() Looper.loop() 来使消息循环起作用,从消息队列里取消息,处理消息 .(如果调用Android的HandlerThread,自动会建立Looper和MessageQueue的消息循环机制)。
2).在线程A中,通过new Handler(线程B.getmyLooper),Handler中mLooper属性指向线程B的Looper。
3).通过Handler把Message发送到线程B的MessageQueue队列中(Handler.sendMessage(Message)),使每个Message中的target又指向Handler本身。
4).经过上述三个步骤,线程A和线程B经过Handler建立起了消息交互机制,线程A把Message发送到线程B后,继续执行自己的操作,把处理消息的事情交由线程B处理,而线程B收到消息后,通过target,调用Handler的回调函数handleMessage().也就是说在线程B中处理handleMessage中的事情。由此实现了消息的异步传递和多线程处理。
2.注意点
1)、new Handler();没有传递参数Looper时,Looper默认为当前线程的Looper(即Handler在哪个线程中new,就取哪个)。
2)、MessageQueue中的Message理论上可以由不同的Handler产生。通过Message的target属性,可以处理不同线程中的Handler。
3)、Handler执行post(Runnable),将把线程压入到一个线程队列中。执行时调用的是Runnable--run方法,但不是start方法,也就是post无法启动一个线程。
4)、通过Handler和Looper之间的关系,可以实现线程之间,线程自己的消息异步发送和接收。(参考示例:Android中Message机制的灵活应用 )
发表评论
-
android的Environment类
2014-01-10 17:04 704String MEDIA_BAD_REMO ... -
Android LayoutInflater详解
2014-01-10 10:41 957在 实际开发中LayoutIn ... -
Android线程模型
2012-02-06 09:01 762Android 进程 在了解A ... -
Android MIME类型
2012-02-02 11:00 1812如同一个web 站点根据 UR ... -
详解 Android 的 Activity 组件
2012-01-31 13:24 732Activity 的生命周期 ... -
Android中Message机制的灵活应用
2012-01-17 11:41 902package com.test; import and ... -
Intent 对象在 Android 开发中的应用
2012-01-13 09:59 1086简介: A ...
相关推荐
Android消息机制是Android系统中处理线程间通信和异步任务的核心组件,它允许应用程序在不同的线程之间安全地交换数据和执行操作。深入理解这一机制对于开发高效、响应迅速的Android应用至关重要。 首先,我们要...
Android消息机制是Android系统中处理线程间通信和异步任务的核心组件,它基于Handler、Looper和Message三个主要组件构建。理解并熟练掌握这一机制对于Android应用开发至关重要,因为这有助于实现高效的UI更新和避免...
本文将深入探讨Android消息机制的核心组件:Handler、Looper和MessageQueue,以及它们如何协同工作。 首先,`Handler`是消息处理的主要角色。它允许我们在一个线程中发送消息到另一个线程,特别是将工作线程中的...
从源码出发,详细的解析了android中的消息机制,分析清楚Looper和MessageQueue以及Handler三者之间的关系。
本文将详细讲解Android消息机制的三个关键类:Looper、Handler和Message,以及它们如何协同工作来处理应用程序中的任务。 首先,`Looper`是线程的魔法师,它使得一个普通的线程能够变成一个可以持续循环处理任务的`...
了解Android消息机制的内部原理,对于设计稳定、高效的多线程应用架构至关重要。 首先,消息机制涉及到几个核心组件:`Message`、`MessageQueue`、`Looper` 和 `Handler`。 `Message`是消息机制中的基础,它是封装...
Android消息机制是Android应用程序开发中的核心机制之一,它涉及线程间通信(IPC)和线程内部的事件驱动,是实现异步消息处理的重要方式。Android消息机制主要基于Handler、Looper和MessageQueue这三个组件协同工作...
总的来说,这个压缩包提供了全面了解和掌握Android消息机制的资源。通过学习源码和阅读文档,你将能够熟练地在Android应用中使用Handler、Looper和Message,实现高效的多线程通信和UI更新。这对你进行Android开发...
这个"最新otto包android消息机制demo"是用于展示Otto在Android应用程序中的使用方法,帮助开发者理解如何利用Otto进行高效、解耦的事件传递。 1. **事件总线概念** 事件总线是一种设计模式,允许应用程序的不同...
### Android消息机制理解及延伸 #### 一、消息机制概览 Android消息机制是Android应用程序中处理异步任务的关键组成部分,它主要涉及到四个核心组件:`Handler`、`Looper`、`Message` 和 `MessageQueue`。这些组件...
总结总结 Android的消息机制Handler是线程间通信的关键工具,它允许开发者在后台线程执行耗时操作,而将UI更新交由主线程处理,保证了UI操作的安全性和性能。理解Handler、Looper和MessageQueue的工作原理以及它们...
在Android系统中,消息机制是多线程环境下保持UI线程(主线程)与工作线程之间同步通信的关键。这个机制允许开发者在非UI线程中执行耗时操作,然后通过消息传递结果到主线程进行界面更新,避免了直接在非UI线程中...
Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。下面就来说说最基本的东西。 Looper 作用: ...
Android消息机制主要指的是Handler的运行机制,是一块很有意思,也很有研究意义的内容。本文计划在较短的篇幅内,通过一定的源码,分析Android消息机制,并在结尾说点”题外话“,帮助我们理解消息机制在安卓应用...
在Android系统中,消息机制是实现组件间通信和线程间通信的重要手段,它涉及到的主要概念有Handler、Message、Looper和MessageQueue。本教程将深入探讨这些关键组件以及它们如何协同工作来确保Android应用程序的正常...