Android 开发: Android 消息处理机制之一: Handler 与 Message

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 开发: Android 消息处理机制之一: Handler 与 Message相关的知识,希望对你有一定的参考价值。

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

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

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的主要内容,如果未能解决你的问题,请参考以下文章

Android开发人员必看的 Handler 消息处理机制(源码实战)

Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验

Android消息处理机制(Handler 与Message)---01

Android系统消息处理机制

Android系统消息处理机制

android 开发Handler源码剖析