最近几讲内容,我们学习了Android中关于多线程的一些知识,上一讲我们讲解了异步任务 AsyncTask 的操作,Android中还提供了其他的线程操作,如Handler Message MessageQueue Looper 等模块,这些就是Android中的消息处理机制。这部分内容是Android学习过程中的重点和难点。
    现在我们就来学习一下Android的消息处理,以及剖析一下相关类如Handler和Message类的源代码,同时使用他们来更新UI主线程的操作。因为Android的消息处理机制内容繁多,我们分为几部分来学习,大家可以关注这几讲内容,这一讲我们重点来学习一下Handler和Message.

一. Handler类介绍

1). 查看Android官网API Handler类

java.lang.Object
    android.os.Handler
Known Direct Subclasses
AsyncQueryHandler, AsyncQueryHandler.WorkerHandler, HttpAuthHandler, SslErrorHandler

一个Handler会允许你发送和处理Message或者Runnable对象关联到一个线程的消息队列MessageQueue中,每一个Handler的实例都会关联一个单一的线程和那个线程的消息队列中。当你创建一个一个新的Handler,它会绑定到你创建的线程和这个线程消息队列中。并且指向好它,它会让消息传递到关联好它的消息队列中,当它从消息队列出队的时候执行它。这里他们的如何关联的不是很懂!

对于Handler来说有两种主要的方式: 1. 计划好消息和Runnable将来的某一个时间点来执行它 2. 从一个不同的线程中执行Handler的入队操作。分发消息由下面的几个方法完成:

1) post(Runnable),
   2) postAtTime(Runnable, long), 
   3) postDelayed(Runnable, long), 
   4) sendEmptyMessage(int), 
   5) sendMessage(Message), 
   6) sendMessageAtTime(Message, long), 
   7) sendMessageDelayed(Message, long)

post方式的方法可以将一个Runable对象排列到消息队列中。sendMessage方式的方法可以通过 Handler的handleMessage(Message) 方法携带有bundle类型的数据的Message对象到队列中(需要你实现Handler的子类)。你可以通过上诉两种方式来出来Handler,你可以允许你的消息在消息队列中准备好就马上被处理,也可以处理之前指定一些延时让你实现超时或者基于时间的行为。
   当你的应用程序的进程被创建的时候,它的主线程专门用来处理正常运行的主线程的消息队列,(也就是说UI主线程有自己的消息队列,所以我们没必要在UI主线程中处理自己的消息)它关心的是管理顶层的应用对象(activities, broadcast receivers, etc)和他们创建的窗口。你可以创建你自己的线程,然后通过Handler与主线程沟通。就像上述说的通过post和sendMessage的方式,Runnable和Message会被计划的执行在Handler的消息队列中适时的进行处理。

二. Message类介绍

1). 查看Android官网API Message类

Java.lang.Object
       android.os.Message

定义一个message包含描述信息和任意的数据对象发送给Handler。这个对象包含两个额外的int类型的属性和一个Object类型的属性,它可以让你不需要去做一些强制类型的转换的操作。如下图所示:

1) arg1 和 arg2 都是Message自带的用来传递一些轻量级存储int类型的数据,比如进度条的数据等。通过这个数据是通过Bundle的方式来转载的,读者可以自己查阅源代码研究。

2) obj 是Message自带的Object类型对象,用来传递一些对象。兼容性最高避免对齐进行类型转换等。

3) replyTo 是作为线程通信的时候使用.

4) what 用户自定义的消息码让接受者识别消息种类,int类型。

【注意】: 获得Message的构造方法最好的方式是调用Message.obtain() 和 Handler.obtainMessage()方法。以便能够更好被回收池所回收[这里读者可以研究一下obtain()的源代码即可明白]。而不是直接用 new Message的方式来获得Message对象。

三. 程序Demo

1. 实现通过 Thread + Handler + Message 的方式下载网络数据。程序结构如下图所示

2. 在Manifest.xml中添加网络权限,这里不再贴出,读者可以参考上面一讲内容

3. 布局文件中 activity_main.xml 中定义Button和ImageView控件,这里不再贴出,读者可以自己下载源代码查看

4. MainActivity.java 程序主代码

[java] view plain copy

 

  1. <span style="font-family:Courier New;">...</span>
  2. /**
  3. * 通过 Handler + Message 的方式下载网络数据
  4. * 通过子线程run()方法中下载数据,使用Message携带数据,然后用Handler发送消息并且处理消息来更新UI.
  5. *
  6. * @author AHuier
  7. */
  8. public class MainActivity extends Activity {
  9. private Button btn;
  10. private ImageView imageView;
  11. private String imgPath = "http://f.hiphotos.baidu.com/image/w%3D2048/sign=05793c21bba1cd1105b675208d2ac9fc/43a7d933c895d14350ee3c3272f082025aaf0703.jpg";
  12. private static final int DOWNLOAD_IMG = 1;
  13. private ProgressDialog dialog = null;
  14. private Handler handler = new Handler() {
  15. // 处理子线程给我们发送的消息。
  16. @Override
  17. public void handleMessage(android.os.Message msg) {
  18. byte[] data = (byte[])msg.obj;
  19. Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
  20. imageView.setImageBitmap(bitmap);
  21. if(msg.what == DOWNLOAD_IMG){
  22. dialog.dismiss();
  23. }
  24. };
  25. };
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_main);
  30. initComponent();
  31. btn.setOnClickListener(new View.OnClickListener() {
  32. @Override
  33. public void onClick(View v) {
  34. // TODO Auto-generated method stub
  35. new Thread(new MyThread()).start();
  36. dialog.show();
  37. }
  38. });
  39. }
  40. @Override
  41. public boolean onCreateOptionsMenu(Menu menu) {
  42. // Inflate the menu; this adds items to the action bar if it is present.
  43. getMenuInflater().inflate(R.menu.main, menu);
  44. return true;
  45. }
  46. private void initComponent() {
  47. btn = (Button) this.findViewById(R.id.button1);
  48. imageView = (ImageView) this.findViewById(R.id.imageView1);
  49. dialog = new ProgressDialog(this);
  50. dialog.setTitle("提示");
  51. dialog.setMessage("正在下载,请稍后...");
  52. dialog.setCancelable(false);
  53. }
  54. // 使用Handler Message MessageQueue Looper等方式去访问网络资源的时候,我们必须要开启一个子线程
  55. public class MyThread implements Runnable{
  56. // 在run方法中完成网络耗时的操作
  57. @Override
  58. public void run() {
  59. HttpClient httpClient = new DefaultHttpClient();
  60. HttpGet httpGet = new HttpGet(imgPath);
  61. HttpResponse httpResponse = null;
  62. try {
  63. httpResponse = httpClient.execute(httpGet);
  64. if(200 == httpResponse.getStatusLine().getStatusCode()){
  65. byte[] data = EntityUtils.toByteArray(httpResponse.getEntity());
  66. // 这里的数据data我们必须发送给UI的主线程,所以我们通过Message的方式来做桥梁。
  67. Message message = Message.obtain();
  68. message.obj = data;
  69. message.what = DOWNLOAD_IMG;
  70. handler.sendMessage(message);
  71. }
  72. } catch (Exception e) {
  73. // TODO: handle exception
  74. }
  75. }
  76. }
  77. }

5. 程序执行结果

四、程序Demo总结

1. 上述Demo中的Handler写法我们只是按图索骥的方式实现比较标准的写法,如果考虑android内存机制的情况下,private Handler的方式定义成为静态的会更好。在Android源码中Handler一般是定义成 protect 权限的。

  2.Handler主要是用来负责发送消息和处理消息的。

3.基于处理,其实这里面蕴含着一个消息队列的概念,这里为什么我们获得消息需要用到Obtain()的方式,而不是通过new的方式构建一个消息,这个问题下一讲我们会通过剖析Message中Obtain()的源代码来讨论。

更多关于Android消息处理机制请点击以下相关链接:

1. Android 消息处理机制之二: Message中obtain()源代码剖析

2. Android 消息处理机制之三: Handler中sendMessage()源代码剖析

源码下载地址:HandlerMessageTest

原文转自:http://blog.csdn.net/ahuier/article/details/17012005

原作者为 AHuier.  请尊重原作者版权

最近几讲内容,我们学习了Android中关于多线程的一些知识,上一讲我们讲解了异步任务 AsyncTask 的操作,Android中还提供了其他的线程操作,如Handler Message MessageQueue Looper 等模块,这些就是Android中的消息处理机制。这部分内容是Android学习过程中的重点和难点。
    现在我们就来学习一下Android的消息处理,以及剖析一下相关类如Handler和Message类的源代码,同时使用他们来更新UI主线程的操作。因为Android的消息处理机制内容繁多,我们分为几部分来学习,大家可以关注这几讲内容,这一讲我们重点来学习一下Handler和Message.

一. Handler类介绍

1). 查看Android官网API Handler类

java.lang.Object
    android.os.Handler
Known Direct Subclasses
AsyncQueryHandler, AsyncQueryHandler.WorkerHandler, HttpAuthHandler, SslErrorHandler

一个Handler会允许你发送和处理Message或者Runnable对象关联到一个线程的消息队列MessageQueue中,每一个Handler的实例都会关联一个单一的线程和那个线程的消息队列中。当你创建一个一个新的Handler,它会绑定到你创建的线程和这个线程消息队列中。并且指向好它,它会让消息传递到关联好它的消息队列中,当它从消息队列出队的时候执行它。这里他们的如何关联的不是很懂!

对于Handler来说有两种主要的方式: 1. 计划好消息和Runnable将来的某一个时间点来执行它 2. 从一个不同的线程中执行Handler的入队操作。分发消息由下面的几个方法完成:

1) post(Runnable),
   2) postAtTime(Runnable, long), 
   3) postDelayed(Runnable, long), 
   4) sendEmptyMessage(int), 
   5) sendMessage(Message), 
   6) sendMessageAtTime(Message, long), 
   7) sendMessageDelayed(Message, long)

post方式的方法可以将一个Runable对象排列到消息队列中。sendMessage方式的方法可以通过 Handler的handleMessage(Message) 方法携带有bundle类型的数据的Message对象到队列中(需要你实现Handler的子类)。你可以通过上诉两种方式来出来Handler,你可以允许你的消息在消息队列中准备好就马上被处理,也可以处理之前指定一些延时让你实现超时或者基于时间的行为。
   当你的应用程序的进程被创建的时候,它的主线程专门用来处理正常运行的主线程的消息队列,(也就是说UI主线程有自己的消息队列,所以我们没必要在UI主线程中处理自己的消息)它关心的是管理顶层的应用对象(activities, broadcast receivers, etc)和他们创建的窗口。你可以创建你自己的线程,然后通过Handler与主线程沟通。就像上述说的通过post和sendMessage的方式,Runnable和Message会被计划的执行在Handler的消息队列中适时的进行处理。

二. Message类介绍

1). 查看Android官网API Message类

Java.lang.Object
       android.os.Message

定义一个message包含描述信息和任意的数据对象发送给Handler。这个对象包含两个额外的int类型的属性和一个Object类型的属性,它可以让你不需要去做一些强制类型的转换的操作。如下图所示:

1) arg1 和 arg2 都是Message自带的用来传递一些轻量级存储int类型的数据,比如进度条的数据等。通过这个数据是通过Bundle的方式来转载的,读者可以自己查阅源代码研究。

2) obj 是Message自带的Object类型对象,用来传递一些对象。兼容性最高避免对齐进行类型转换等。

3) replyTo 是作为线程通信的时候使用.

4) what 用户自定义的消息码让接受者识别消息种类,int类型。

【注意】: 获得Message的构造方法最好的方式是调用Message.obtain() 和 Handler.obtainMessage()方法。以便能够更好被回收池所回收[这里读者可以研究一下obtain()的源代码即可明白]。而不是直接用 new Message的方式来获得Message对象。

三. 程序Demo

1. 实现通过 Thread + Handler + Message 的方式下载网络数据。程序结构如下图所示

2. 在Manifest.xml中添加网络权限,这里不再贴出,读者可以参考上面一讲内容

3. 布局文件中 activity_main.xml 中定义Button和ImageView控件,这里不再贴出,读者可以自己下载源代码查看

4. MainActivity.java 程序主代码

[java] view plain copy

 

  1. <span style="font-family:Courier New;">...</span>
  2. /**
  3. * 通过 Handler + Message 的方式下载网络数据
  4. * 通过子线程run()方法中下载数据,使用Message携带数据,然后用Handler发送消息并且处理消息来更新UI.
  5. *
  6. * @author AHuier
  7. */
  8. public class MainActivity extends Activity {
  9. private Button btn;
  10. private ImageView imageView;
  11. private String imgPath = "http://f.hiphotos.baidu.com/image/w%3D2048/sign=05793c21bba1cd1105b675208d2ac9fc/43a7d933c895d14350ee3c3272f082025aaf0703.jpg";
  12. private static final int DOWNLOAD_IMG = 1;
  13. private ProgressDialog dialog = null;
  14. private Handler handler = new Handler() {
  15. // 处理子线程给我们发送的消息。
  16. @Override
  17. public void handleMessage(android.os.Message msg) {
  18. byte[] data = (byte[])msg.obj;
  19. Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
  20. imageView.setImageBitmap(bitmap);
  21. if(msg.what == DOWNLOAD_IMG){
  22. dialog.dismiss();
  23. }
  24. };
  25. };
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_main);
  30. initComponent();
  31. btn.setOnClickListener(new View.OnClickListener() {
  32. @Override
  33. public void onClick(View v) {
  34. // TODO Auto-generated method stub
  35. new Thread(new MyThread()).start();
  36. dialog.show();
  37. }
  38. });
  39. }
  40. @Override
  41. public boolean onCreateOptionsMenu(Menu menu) {
  42. // Inflate the menu; this adds items to the action bar if it is present.
  43. getMenuInflater().inflate(R.menu.main, menu);
  44. return true;
  45. }
  46. private void initComponent() {
  47. btn = (Button) this.findViewById(R.id.button1);
  48. imageView = (ImageView) this.findViewById(R.id.imageView1);
  49. dialog = new ProgressDialog(this);
  50. dialog.setTitle("提示");
  51. dialog.setMessage("正在下载,请稍后...");
  52. dialog.setCancelable(false);
  53. }
  54. // 使用Handler Message MessageQueue Looper等方式去访问网络资源的时候,我们必须要开启一个子线程
  55. public class MyThread implements Runnable{
  56. // 在run方法中完成网络耗时的操作
  57. @Override
  58. public void run() {
  59. HttpClient httpClient = new DefaultHttpClient();
  60. HttpGet httpGet = new HttpGet(imgPath);
  61. HttpResponse httpResponse = null;
  62. try {
  63. httpResponse = httpClient.execute(httpGet);
  64. if(200 == httpResponse.getStatusLine().getStatusCode()){
  65. byte[] data = EntityUtils.toByteArray(httpResponse.getEntity());
  66. // 这里的数据data我们必须发送给UI的主线程,所以我们通过Message的方式来做桥梁。
  67. Message message = Message.obtain();
  68. message.obj = data;
  69. message.what = DOWNLOAD_IMG;
  70. handler.sendMessage(message);
  71. }
  72. } catch (Exception e) {
  73. // TODO: handle exception
  74. }
  75. }
  76. }
  77. }

5. 程序执行结果

四、程序Demo总结

1. 上述Demo中的Handler写法我们只是按图索骥的方式实现比较标准的写法,如果考虑android内存机制的情况下,private Handler的方式定义成为静态的会更好。在Android源码中Handler一般是定义成 protect 权限的。

  2.Handler主要是用来负责发送消息和处理消息的。

3.基于处理,其实这里面蕴含着一个消息队列的概念,这里为什么我们获得消息需要用到Obtain()的方式,而不是通过new的方式构建一个消息,这个问题下一讲我们会通过剖析Message中Obtain()的源代码来讨论。

更多关于Android消息处理机制请点击以下相关链接:

1. Android 消息处理机制之二: Message中obtain()源代码剖析

2. Android 消息处理机制之三: Handler中sendMessage()源代码剖析

源码下载地址:HandlerMessageTest

原文转自:http://blog.csdn.net/ahuier/article/details/17012005

原作者为 AHuier. 请尊重原作者版权

【Android 开发】: Android 消息处理机制之一: Handler 与 Message的更多相关文章

  1. Android的消息处理机制,handler,message,looper(一)

    当应用程序启动时,Android首先会开启一个主线程(也就是UI线程),主线程为管理界面中的UI控件.在程序开发时,对于比较耗时的操作,通常会为其开辟一个单独的线程来执行,以尽可能减少用户的等待时间. ...

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

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

  3. Android开发学习之路-使用Handler和Message更新UI

    在Android中,在非主线程中更新UI控件是不安全的,app在运行时会直接Crash,所以当我们需要在非主线程中更新UI控件,那么就需要用到Handler和Message来实现 Demo中,使用到一 ...

  4. Android的消息处理机制Looper,Handler,Message

    android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...

  5. 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

    PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...

  6. Android的消息循环机制 Looper Handler类分析

    Android的消息循环机制 Looper Handler类分析 Looper类说明   Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...

  7. Android 消息机制 (Handler、Message、Looper)

    综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidne ...

  8. Android开发——Android多进程以及使用场景介绍

    个层级,具体可以查看Android开发--Android进程保活招式大全中1.1部分的内容,这里就不赘述了. 根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最高级别.例如 ...

  9. Android开发-Android Studio问题以及解决记录

    [Android开发] Android Studio问题以及解决记录   http://blog.csdn.net/niubitianping/article/details/51400721 1.真 ...

随机推荐

  1. Java Hello World例子和添加按钮事件与功能

    新建android工程,然后默认“下一步”即可完成创建: 2.添加Button 3.在src的MainActivity.java添加以下红色代码 import android.support.v7.a ...

  2. 还是不想改报告,伊阿忆啊哟-Linux基础继续

    hi 虽然今天是最最美好的周六(前不着工作日后不着工作日),但老子还要来改报告,但额就是不想改,你拿我有啥办法啊... 争取完结Linux基础 一.Linux常用命令(三) 4.帮助命令 4.1 帮助 ...

  3. 原生的强大DOM选择器querySelector

    在传统的 JavaScript 开发中,查找 DOM 往往是开发人员遇到的第一个头疼的问题,原生的 JavaScript 所提供的 DOM 选择方法并不多,仅仅局限于通过 tag, name, id ...

  4. UESTC 764 失落的圣诞节 --RMQ/线段树

    题意:n种物品,每种物品对不同的人都有不同的价值,有三个人选,第一个为普通学生,第二个是集,第三个是祈,集和祈可以选一样的,并且还会获得加分,集和祈选的普通学生都不能选,问三个人怎样选才能使总分最高. ...

  5. 校园导游系统(C++实现,VC6.0编译,使用EasyX图形库)

    运行效果: 说明: 由于当年还不会使用多线程,所以很多获取用户点击的地方都是使用循环实现的...CPU占用率会比较高. 代码: //校园导游系统.cpp 1 #include <graphics ...

  6. CF687C. The Values You Can Make[背包DP]

    C. The Values You Can Make time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  7. Codeforces 687B. Remainders Game[剩余]

    B. Remainders Game time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  8. single单例模式

    单例模式:多用于数据库连接,保证数据库只连接一次,避免重复连接.因为多次打开服务器会造成服务器负担,运行速度会减慢. 以下是一个连接数据库的单例模式: <?php class db_mysql{ ...

  9. HTML 学习笔记(链接)

    HTML链接 超链接可以是一个字,一个词,或者一组词,也可以是一幅图像,您可以点击这些内容来跳转到新的文档或者当前文档中的某个部分. 当您把鼠标指针移动到网页中的某个链接上时,箭头会变为一只小手. 我 ...

  10. jmeter(一)基础介绍

    参考书籍:段念<软件性能测试与案例剖析>——第二版 推荐一本书<零成本实现web性能测试——基于Apache—jmeter>,主要内容是一些关于jmeter的实战使用,想学习的 ...