Message(消息):
 
    一. Message的字段:
   在Android中,Message作为线程之间(主要是子线程和UI主线程之间)数据交换的载体,通过Handler去传递。它包含几个常用的字段:

    1.arg1和arg2两个int类型的字段:主要在线程之间需要传递简单的int类型的数据时使用。
    2.what字段:int类型,主要用于标识一个Message。当在子线程中定义一个Message时,通常指定what的值为一个int常量,该Message传递到主线程时,我们通过what的值识别该Message。
    3.obj字段:是一个任意类型的对象,线程之间要交换的数据,主要是通过该字段来存储。
 
    二. 获得Massage对象

 
    1. 通过构造函数获得Message对象,Message有一个构造函数:
  public Message(){}; 
    通过该构造函数可以获得Massage对象,但是官方主要推荐通过Message.obtain()和Handler.obtainMessage()来获得Message对象,Message.obtain()有多个重载方法。使用Message的构造函数来创建Message对象需要重新分配一块新的内容,而通过Message.obtain()和Handler.obtainMessage()方法主要从全局消息槽中使用被回收的对象来创建Message,这样节省了一定的内存。
 
    例子:在子线程中通过Message构造函数创建Message对象,并通过Handler传递到主线程中。
  1. package zst.message01;
  2. import android.os.Bundle;
  3. import android.os.Handler;
  4. import android.os.Message;
  5. import android.app.Activity;
  6. import android.view.Menu;
  7. import android.view.View;
  8. import android.view.View.OnClickListener;
  9. import android.widget.Button;
  10. public class MainActivity extends Activity implements OnClickListener {
  11. private Button button01;
  12.  
  13. public static final int ONE = 1;
  14.  
  15. //在主线程中创建的Handler对象,通常定义成static
  16. public static Handler handler = new Handler(){
  17. @Override
  18. public void handleMessage(Message msg) {
  19. switch (msg.what) {
  20. case ONE:
  21. System.out.println("第一个Message-->" + "arg1=" + msg.arg1 + ",arg2=" + msg.arg2 + ",obj=" + msg.obj);
  22. break;
  23. default:
  24. break;
  25. }
  26. }
  27.  
  28. };
  29.  
  30. @Override
  31. protected void onCreate(Bundle savedInstanceState) {
  32. super.onCreate(savedInstanceState);
  33. setContentView(R.layout.activity_main);
  34. button01 = (Button) findViewById(R.id.button01);
  35. button01.setOnClickListener(this);
  36. }
  37.  
  38. @Override
  39. public void onClick(View v) {
  40. if(v.getId() == R.id.button01){
  41. //启动一个子线程
  42. new Thread(new Runnable() {
  43.  
  44. @Override
  45. public void run() {
  46. //获得Message对象的第一种方法:使用构造函数创建Message,这种方法不推荐使用
  47. Message message = new Message();
  48. message.arg1 = 100;
  49. message.arg2 = 200;
  50. message.what = ONE; //用于标识Message
  51. message.obj = "Message_01";
  52. //发送Message到主线程中
  53. handler.sendMessage(message);
  54.  
  55. }
  56.  
  57. }).start();
  58.  
  59. }
  60.  
  61. }
  62. }
     
  输出:
 
 
  2. 通过 public static Message obtain() 方法获得Message对象
  1. //获得Message对象的第二种方法
  2. Message message = Message.obtain();
  3. message.arg1 = 100;
  4. message.arg2 = 200;
  5. message.what = TWO; //用于标识Message
  6. message.obj = "Message_02";
  7. handler.sendMessage(message);

   public static Message obtain()方法的源码如下:

  1. // sometimes we store linked lists of these things
  2. /*package*/ Message next;
  3. private static final Object sPoolSync = new Object();
  4. private static Message sPool;
  5. private static int sPoolSize = 0;
  6. private static final int MAX_POOL_SIZE = 50;
  7. /**
  8. * Return a new Message instance from the global pool. Allows us to
  9. * avoid allocating new objects in many cases.
  10. */
  11. public static Message obtain() {
  12. synchronized (sPoolSync) {
  13. if (sPool != null) {
  14. Message m = sPool;
  15. sPool = m.next;
  16. m.next = null;
  17. sPoolSize--;
  18. return m;
  19. }
  20. }
  21. return new Message();
  22. }

   该方法将从全局消息槽中获得一个Message对象,从而避免再分配一块新的内存来创建Message对象。从上面可以看出,当全局消息槽中当前sPool不为null,则把sPool指向的Message对象赋给一个Message的临时引用,然后sPool再指向槽中的下一个Message,最后把临时引用m指向的Message对象返回给我们,这样全局消息槽中的Message可以得到重复使用,从而节省了一定的内存。如果sPool为null时,即消息槽为空,没有Message,这时才调用Message的构造函数来创建一个Message对象给我们。

 
    3. 通过 public static Message obtain(Handler h) 方法获得Message对象
  1.         //获得Message对象的第三种方法:
  2. Message message = Message.obtain(handler);
  3. message.arg1 = 100;
  4. message.arg2 = 200;
  5. message.what = THREE; //用于标识Message
  6. message.obj = "Message_03";
  7. //发送Message
  8. message.sendToTarget();

  public static Message obtain(Handler h)方法的源码如下:

  1. /**
  2. * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
  3. * @param h Handler to assign to the returned Message object's <em>target</em> member.
  4. * @return A Message object from the global pool.
  5. */
  6. public static Message obtain(Handler h) {
  7. Message m = obtain();
  8. m.target = h;
  9. return m;
  10. }

  从上面源码中可以看出:该方法内部还是通过public static Message obtain()方法从全局消息槽中返回一个Message对象给我们,然后把传入的Handler对象参数当成发送和接收该Message对象的目标Handler对象。由于该方法内部已经指定了处理Message对象的目标Handler对象,所以在发送Message消息时,不会再调用Handler对象的sendMessage(message)方法,而是直接使用Message对象的sendToTarget()方法发送。

 
    4. 通过public static Message obtain(Handler h, int what)方法获得
  1.       //获得Message对象的第四种方法:
  2. Message message = Message.obtain(handler, FOUR);
  3. message.arg1 = 100;
  4. message.arg2 = 200;
  5. message.obj = "Message_04";
  6. message.sendToTarget();

  public static Message obtain(Handler h, int what)方法的源码如下:

  1. /**
  2. * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
  3. * <em>what</em> members on the Message.
  4. * @param h Value to assign to the <em>target</em> member.
  5. * @param what Value to assign to the <em>what</em> member.
  6. * @return A Message object from the global pool.
  7. */
  8. public static Message obtain(Handler h, int what) {
  9. Message m = obtain();
  10. m.target = h;
  11. m.what = what;
  12. return m;
  13. }
     从上面的源码可以看出:该方法的源码和public static Message obtain(Handler h)方法的源码类似,都是先通过public static Message obtain()方法从全局消息槽中获得Message对象,再指定目标Handler对象,同时也指定Message的what字段值。
   
  还有其他三个obtain()的重载方法也是这样,不同点是在创建Message对象时,同时指定Message的不同字段值。如下:
     public static Message obtain(Handler h, int what, Object obj)方法源码:
  1. /**
  2. * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
  3. * members.
  4. * @param h The <em>target</em> value to set.
  5. * @param what The <em>what</em> value to set.
  6. * @param obj The <em>object</em> method to set.
  7. * @return A Message object from the global pool.
  8. */
  9. public static Message obtain(Handler h, int what, Object obj) {
  10. Message m = obtain();
  11. m.target = h;
  12. m.what = what;
  13. m.obj = obj;
  14. return m;
  15. }

  public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj)方法源码:

  1. /**
  2. * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
  3. * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
  4. *
  5. * @param h The <em>target</em> value to set.
  6. * @param what The <em>what</em> value to set.
  7. * @param arg1 The <em>arg1</em> value to set.
  8. * @param arg2 The <em>arg2</em> value to set.
  9. * @param obj The <em>obj</em> value to set.
  10. * @return A Message object from the global pool.
  11. */
  12. public static Message obtain(Handler h, int what,
  13. int arg1, int arg2, Object obj) {
  14. Message m = obtain();
  15. m.target = h;
  16. m.what = what;
  17. m.arg1 = arg1;
  18. m.arg2 = arg2;
  19. m.obj = obj;
  20. return m;
  21. }

  public static Message obtain(Handler h, int what, int arg1, int arg2)方法源码:

  1. /**
  2. * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
  3. * <em>arg1</em>, and <em>arg2</em> members.
  4. *
  5. * @param h The <em>target</em> value to set.
  6. * @param what The <em>what</em> value to set.
  7. * @param arg1 The <em>arg1</em> value to set.
  8. * @param arg2 The <em>arg2</em> value to set.
  9. * @return A Message object from the global pool.
  10. */
  11. public static Message obtain(Handler h, int what, int arg1, int arg2) {
  12. Message m = obtain();
  13. m.target = h;
  14. m.what = what;
  15. m.arg1 = arg1;
  16. m.arg2 = arg2;
  17. return m;
  18. }
   
 三. Message还可以携带Bundle对象
    添加Bundle对象
  1.     Message message = Message.obtain(handler, EIGHT, 100, 200);
  2. message.obj = "Message_08";
  3. Bundle b = new Bundle();
  4. b.putString("name", "张三");
  5. message.setData(b);
  6. message.sendToTarget();
    取出Bundle对象
  String name = msg.getData().getString("name") 
 
 
例子源码:D:\Android\workspace\ThreadAndAsync\Message01
 
 
 

Android多线程编程<二>Handler异步消息处理机制之Message的更多相关文章

  1. Android Handler 异步消息处理机制的妙用 创建强大的图片加载类(转)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 最近创建了一个群,方便大家交流,群号: ...

  2. Android Handler 异步消息处理机制的妙用 创建强大的图片载入类

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...

  3. Android之Handler(异步消息处理)机制

    1. 概述 Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念.那么什么叫异步消息处理线程呢?异步消息处理线程启动后会进入一个无限的循环体之中,每循 ...

  4. Android多线程编程<一>Android中启动子线程的方法

          我们知道在Android中,要更新UI只能在UI主线程去更新,而不允许在子线程直接去操作UI,但是很多时候,很多耗时的工作都交给子线程去实现,当子线程执行完这些耗时的工作后,我们希望去修改 ...

  5. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. Android异步消息处理机制(多线程)

    当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如果不将这类操作放在子线程里去执行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用. ...

  7. 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...

  8. Android 异步消息处理机制 让你在深入了解 Looper、Handler、Message之间的关系

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 非常多人面试肯定都被问到过,请问And ...

  9. Android线程与异步消息处理机制

    在程序开发时,对于一些比较耗时的操作,我们通常会为其开辟一个单独的线程来执行,这样可以尽可能的减少用户等待的时间.在Android中,默认情况下,所有的操作都是在主线程中进行的,这个主线程负责管理与U ...

随机推荐

  1. [leetcode]67. Add Binary 二进制加法

    Given two binary strings, return their sum (also a binary string). The input strings are both non-em ...

  2. setsockopt设置socket状态

    setsockopt设置socket状态 1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsoc ...

  3. [BeijingWc2008]雷涛的小猫

    --BZOJ1270 Description 雷涛的小猫雷涛同学非常的有爱心,在他的宿舍里,养着一只因为受伤被救助的小猫(当然,这样的行为是违反学生宿舍管理条例的). 在他的照顾下,小猫很快恢复了健康 ...

  4. Docker Hello World

    Docker 允许你在容器内运行应用程序,使用docker run命令来在容器内运行一个个应用程序. 输出Hello World docker run ubuntu:15.10 ./bin/echo ...

  5. 学习blinker

    from blinker import signal do_sth = signal('do_sth') #创建信号 def process(f, a, b, **kwargs): f(a, b, * ...

  6. Chapter3_操作符_直接常量和指数计数法

    (1)直接常量 在程序中使用直接常量,相当于指导编译器,告诉它要生成什么样的类型,这样就不会产生模棱两可的情况.比如flaot a = 1f等,后缀表示告诉编译器想生成的类型.常用的后缀有l/L(lo ...

  7. centos7 安装maven

    进入指定目录 cd /usr/local/src/   下载maven 包 wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.1.1/bin ...

  8. C#部分试题实例

    1.在C#中,下列选项中自定义方法的语句错误的是().(选择一项) 正确答案:AD 解析:本题考查自定义方法的定义及调用.A项void是无返回值类型,D项定义方法的时候没有写返回值类型:故选AD. 2 ...

  9. Hessian 使用例子

    一.协议包(数据对象需要实现序列化接口,可以用于服务端接口.客户端调用服务之用) /** * */ package com.junge.demo.protocol.model; import java ...

  10. bash编程-条件测试

    Shell脚本中经常需要判断某情况或者数据是否满足,需要由测试机制来实现. 测试方式 echo $?查看命令执行状态返回值 bash脚本中可以自定义返回值exit n(n为自己指定的状态码),shel ...