安卓开发_深入理解Handler消息传递机制

一、概述

因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面

二、消息类(Message)

消息类是存放在MessageQueue中的,而一个MessageQueue中可以包含多个Message对象

每一个Message对象可以通过Message.obtain()或者Handler.obtainMessage()方法获得

一个Message具有的属性:


属性


类型


介绍


arg1


int


存放整型数据


arg2


int


存放整型数据


obj


Object


存放Object类型的任意对象


replyTo


Message


指定此Message发送到哪里的可选Message对象


what          


int


指定用户自定义的消息代码,接受者可以了解这个消息的信息

一个Message对象可以携带int类型的数据,而如果要携带其他类型的数据,可以将要携带的数据保存到Bundle对象中,然后通过Message类的setDate()方法将其添加到Message中

注:

1、尽量使用Message.what标识信息,方便用于不同的方式处理Message

2、通常情况下,尽量使用Message.obtain()或者Handler.obtainMessage()方法从消息池中获得空消息对象,以便节省资源,而不是使用Message的默认构造方法

3、当一个Message对象只需要携带int型数据的时候,优先使用Message.arg1或Message.arg2属性,这要比用Bundle携带int数据节省内存

三、消息处理类(Handler)

Handler 允许 发送或者处理 Message或者Runnable 类的对象到其(Handler)所在线程的MessageQueue中

主要有两个作用:

1、连接主线程和子线程进行通信(UI线程和工作线程通信)

2、将Message对象 通过post()或者sendMessage()方法发送到MessageQueue中,

当MessageQueue循环到该对象时,调用相应的Handler对象的handlerMessage()方法进行处理

Handler类提供的部分方法:


方法


介绍


handleMessage(Message msg)


处理消息的方法。

通常使用该方法处理消息,

在发送消息时,该方法会自动回调


Post(Runnable r)


立即发送Runnable对象,

注:该Runnable对象最终将被封装成Mwssage对象


PostAtTime(Runnable r,long uptimeMillis)


定时发送Runnable对象,

注:该Runnable对象最终将被封装成Mwssage对象


postDelayed(Runnable r,long delayMillis)


延迟发送Runnable对象,

注:该Runnable对象最终将被封装成Mwssage对象


sendEmptyMessage(int what)


发送空消息


sendMessage(Message msg)


立即发送消息


sendMessageAtTime(Message msg)


定时发送消息


sendMessageDelayed(Message msg,long delayMillis)


延迟发送消息

注:在一个线程中,只能有一个Looper和MessageQueue,却可以有多个Handler,这些Handler共享同一个Looper和MessageQueue

四、循环着(Looper)

1、从上面只是可以知道:一个线程中,只能有一个Looper和MessageQueue。

也就是说一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列),一个MessageQueue又存放着多条Message

注意:MessageQueue中,消息的存放时FIFO(先进先出)的。

2、Looper对象是为了一个线程开启一个消息循环,来操作MessageQueue

注:在主线程中,系统会为主线程自动创建一个Looper对象来开启消息循环。而在非主线程中,是没有Looper对象的,没有Looper对象就不能创建Handler对象

so,在主线程中直接创建Handler对象是可以的。但是在非主线程中创建Handler对象则会产生异常

3、如果需要在非主线创建Handler对象

(1)使用Looper类的prepare()方法来初始化一个Looper对象

(2)创建Handler对象

(3)使用Looper类的loop()方法启动Looper,开启消息循环

                   //需要先有Looper对象
            Looper.prepare();//会创建一个Looper对象,并把该对象放入到该线程的本地变量中,在Looper的构造方法中创建了MessageQueue对象
            //在子线程中实例化handler,子线程中没有Looper对象 

            handler = new Handler(){

            };//如果直接实例化Handler,会异常 new RuntimeException,原因是子线程中没有Looper对象 

            //让Looper对象循环读取MessageQueue中的消息
            //循环从队列中读取消息,当读到消息时,会去调用   msg.target.dispatchMessage(msg);
            //在Message类中有一个target成员,当发送消息时,target成员被赋值为当前的 handler对象
            Looper.loop();

Looper提供的部分方法:


方法


描述


prepare()


用于初始化Looper


loop()


启动Looper线程,线程循环消息队列(MessageQueue)获取和处理信息


myLooper()


获得当前线程的Looper对象


getThread


获得Looper对象所属的线程


quit()


结束Looper循环

*注*:Looper.loop()方法,这个方法是循环消息队列!即这个方法内部相当于正在执行一个死循环,所以在Looper.loop()代码之后的代码都不会执行

,而只有再调用 Looper.quit()之后才会执行后面的代码

-------------------------------------------------------------华丽的分割线------------------------------------------------------------------

让我们看几个例子来深入理解下Handler消息传递机制

1、在主线程中启动一个子线程下载图片,子线程传消息递给主线程,让主线程处理。(了解子线程发送Runnable对象和发送Message对象的两种方法)

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     android:gravity="center_horizontal"
 7      >
 8
 9     <ImageView
10         android:layout_width="200dp"
11         android:layout_height="200dp"
12         android:id="@+id/show_image"
13         android:src="@drawable/ic_launcher"
14         />
15
16     <Button
17         android:layout_width="wrap_content"
18         android:layout_height="wrap_content"
19         android:id="@+id/down_image"
20         android:text="下载"
21         />
22
23 </LinearLayout>

布局文件代码

(1)发送Message对象的方法

 1 package com.xqx.handle;
 2
 3 import java.io.IOException;
 4
 5 import org.apache.http.HttpResponse;
 6 import org.apache.http.client.ClientProtocolException;
 7 import org.apache.http.client.HttpClient;
 8 import org.apache.http.client.methods.HttpGet;
 9 import org.apache.http.impl.client.DefaultHttpClient;
10 import org.apache.http.util.EntityUtils;
11
12 import android.app.Activity;
13 import android.graphics.Bitmap;
14 import android.graphics.BitmapFactory;
15 import android.os.Bundle;
16 import android.os.Handler;
17 import android.os.Message;
18 import android.view.View;
19 import android.view.View.OnClickListener;
20 import android.widget.Button;
21 import android.widget.ImageView;
22
23
24 public class MainActivity extends Activity {
25     private String path = "http://images2015.cnblogs.com/blog/493196/201509/493196-20150911220222090-1272536050.jpg";//图片下载地址
26     private ImageView showImage;
27     private Button downImage;
28     //哪一个线程是接受消息的,就在哪个线程中实例化Handler对象
29     //因为主线程中,系统会为自动创建Looper对象,开启循环消息,所以只需要在主线程中定义Handler对象
30     private Handler handler = new Handler(){
31         @Override //处理消息的方法,当消息发送过来时,该方法自动回调
32         public void handleMessage(android.os.Message msg) {
33             //处理方法,将图片显示在ImageView中
34             showImage.setImageBitmap((Bitmap) msg.obj);
35
36         };
37     };
38     @Override
39     protected void onCreate(Bundle savedInstanceState) {
40         // TODO Auto-generated method stub
41         super.onCreate(savedInstanceState);
42         setContentView(R.layout.activity_main);
43
44         showImage = (ImageView) findViewById(R.id.show_image);
45         downImage = (Button) findViewById(R.id.down_image);
46
47         downImage.setOnClickListener(new OnClickListener() {
48
49             @Override
50             public void onClick(View v) {
51                 // TODO Auto-generated method stub
52                 //开启一个线程下载图片
53                 new Thread(new Runnable() {
54
55                     @Override
56                     public void run() {
57                         // TODO Auto-generated method stub
58                         HttpGet get = new HttpGet(path);
59                         HttpClient client = new DefaultHttpClient();
60                         HttpResponse response = null;
61
62                         try {
63                             response = client.execute(get);
64                             if(response.getStatusLine().getStatusCode()==200)
65                             {
66                                 //获得下载后的图片的字节数据
67                                 byte b[] = EntityUtils.toByteArray(response.getEntity());
68                                 //将图片字节数据转换成Bitmap格式
69                                  Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
70                                  //下载完成,将图片发送给主线程
71                                  //从MessageQueue中获取可用的Message对象,如果没有可用的,则会创建一个新的Message对象
72                                  Message msg = Message.obtain();
73                                  //把发送的图片放到msg对象中
74                                  msg.obj = bitmap;
75                                  //使用Handler.sendMessage(Message msg)方法传递消息
76                                  handler.sendMessage(msg);
77                             }
78
79
80                         } catch (ClientProtocolException e) {
81                             // TODO Auto-generated catch block
82                             e.printStackTrace();
83                         } catch (IOException e) {
84                             // TODO Auto-generated catch block
85                             e.printStackTrace();
86                         }
87
88
89                     }
90                 }).start();//不要忘记开启线程
91             }
92         });
93
94     }
95
96
97 }

Handler.sendMessage(Message msg)

(2)、发送Runnable对象的方法

 1 package com.xqx.handle;
 2
 3 import java.io.IOException;
 4
 5 import org.apache.http.HttpResponse;
 6 import org.apache.http.client.ClientProtocolException;
 7 import org.apache.http.client.HttpClient;
 8 import org.apache.http.client.methods.HttpGet;
 9 import org.apache.http.impl.client.DefaultHttpClient;
10 import org.apache.http.util.EntityUtils;
11
12 import android.app.Activity;
13 import android.graphics.Bitmap;
14 import android.graphics.BitmapFactory;
15 import android.os.Bundle;
16 import android.os.Handler;
17 import android.os.Message;
18 import android.view.View;
19 import android.view.View.OnClickListener;
20 import android.widget.Button;
21 import android.widget.ImageView;
22
23
24 public class Handler2 extends Activity {
25     private String path = "http://images2015.cnblogs.com/blog/493196/201509/493196-20150911220222090-1272536050.jpg";//图片下载地址
26     private ImageView showImage;
27     private Button downImage;
28     //哪一个线程是接受消息的,就在哪个线程中实例化Handler对象
29     //因为主线程中,系统会为自动创建Looper对象,开启循环消息,所以只需要在主线程中定义Handler对象
30     private Handler handler = new Handler();
31     @Override
32     protected void onCreate(Bundle savedInstanceState) {
33         // TODO Auto-generated method stub
34         super.onCreate(savedInstanceState);
35         setContentView(R.layout.activity_main);
36
37         showImage = (ImageView) findViewById(R.id.show_image);
38         downImage = (Button) findViewById(R.id.down_image);
39
40         downImage.setOnClickListener(new OnClickListener() {
41
42             @Override
43             public void onClick(View v) {
44                 // TODO Auto-generated method stub
45                 //开启一个线程下载图片
46                 new Thread(new Runnable() {
47
48                     private Bitmap bitmap;
49
50                     @Override
51                     public void run() {
52                         // TODO Auto-generated method stub
53                         HttpGet get = new HttpGet(path);
54                         HttpClient client = new DefaultHttpClient();
55                         HttpResponse response = null;
56
57                         try {
58                             response = client.execute(get);
59                             if(response.getStatusLine().getStatusCode()==200)
60                             {
61                                 //获得下载后的图片的字节数据
62                                 byte b[] = EntityUtils.toByteArray(response.getEntity());
63                                 bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
64                                  //下载完成,将图片发送给主线程
65                                 //Handler.post(Runnable r)方法
66                                  handler.post(new Runnable() {
67
68                                     @Override
69                                     public void run() {
70                                         // TODO Auto-generated method stub
71                                         showImage.setImageBitmap(bitmap);
72                                     }
73                                 });
74                             }
75
76
77                         } catch (ClientProtocolException e) {
78                             // TODO Auto-generated catch block
79                             e.printStackTrace();
80                         } catch (IOException e) {
81                             // TODO Auto-generated catch block
82                             e.printStackTrace();
83                         }
84
85
86                     }
87                 }).start();//不要忘记开启线程
88             }
89         });
90
91     }
92
93
94 }

Handler.post(Runnable r)

最后因为下载网络图片,不要忘记在清单文件中 添加网络访问权限

    <uses-permission android:name="android.permission.INTERNET"/>

效果图:

下载前:

下载后:

时间: 2024-10-02 23:35:21

安卓开发_深入理解Handler消息传递机制的相关文章

安卓开发_深入理解广播机制

一.Broadcast(广播) 在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理.另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收. (百度百科) 二.BroadcastReceiver(广播接收器) 1.自定义BroadcastReceiver 自定义广播

安卓开发_深入理解Content Provider

一.Content Provider概述 Content Provider用于保存和获取数据,并使其对所有应用程序可见,这是不同应用程序之间共享数据的唯一方式,因为在Android中没有提供所有应用可以共同访问的公共存储区域 1.  Content Provider内部的数据如何保存是由其设计者决定的,而所有的的Content Provider都实现一组通用的方法,用来提供数据的增删改查操作 2.  客户端如果要使用这些操作方法,可以通过ContentProvider对象实现对 Content

安卓开发_数据存储技术_sqlite

一.SQLite SQLite第一个Alpha版本诞生于2000年5月,它是一款轻量级数据库,它的设计目标是嵌入式的,占用资源非常的低,只需要几百K的内存就够了.SQLite已经被多种软件和产品使用 二.SQLite特性 1 2 1.轻量级 3 SQLite和C\S模式的数据库软件不同,它是进程内的数据库引擎,因此不存在数据库的客户端和服务器.使用SQLite一般只需要带上它的一个动态库,就可以享受它的全部功能.而且那个动态库的尺寸也相当小. 4 2.独立性 5 SQLite数据库的核心引擎本身

安卓开发_浅谈ListView(自定义适配器)

ListView作为一个实际开发中使用率非常高的视图,一般的系统自带的适配器都无法满足开发中的需求,这时候就需要开发人员来自定义适配器使得ListView能够有一个不错的显示效果 有这样一个Demo ,实现图片文字混合列表 1 package com.example.work; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 7 8 import android.R.in

Android基础入门教程——3.3 Handler消息传递机制浅析

Android基础入门教程--3.3 Handler消息传递机制浅析 标签(空格分隔): Android基础入门教程 本节引言 前两节中我们对Android中的两种事件处理机制进行了学习,关于响应的事件响应就这两种:本节给大家讲解的 是Activity中UI组件中的信息传递Handler,相信很多朋友都知道,Android为了线程安全,并不允许我们在UI线程外操作UI:很多时候我们做界面刷新都需要通过Handler来通知UI组件更新!除了用Handler完成界面更新外,还可以使用runOnUiT

安卓开发_浅谈Android动画(四)

Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1.  ValueAnimator 基本属性动画类 方法 描述 setDuration(long duration) 设置动画持续时间的方法 setEvaluator(TypeEvaluator value) 设置插值计算的类型 setInterpolator(TimeInterpolator value) 设置时间插值器的类型 addUp

Android Handler消息传递机制

1. Handler消息传递机制初步认识:什么是Handler? handler通俗一点讲就是用来在各个线程之间发送数据的处理对象.在任何线程中,只要获得了另一个线程的handler,则可以通过 handler.sendMessage(message)方法向那个线程发送数据.基于这个机制,我们在处理多线程的时候可以新建一个thread,这个thread拥有UI线程中的一个handler.当thread处理完一些耗时的操作后通过传递过来的handler向UI线程发送数据,由UI线程去更新界面. 主

安卓开发_慕课网_百度地图_添加覆盖物

学习内容来自“慕课网” 本片学习内容接自前四篇基础 安卓开发_慕课网_百度地图 安卓开发_慕课网_百度地图_实现定位 安卓开发_慕课网_百度地图_实现方向传感器 安卓开发_慕课网_百度地图_实现模式转换 请先学习前4篇再学习本篇,因为本篇在前四篇的基础上进行代码的编写 一.新建一个类用来存放数据(距离,点赞数,介绍图等信息) 1 package com.example.map; 2 3 import java.io.Serializable; 4 import java.util.ArrayLi

Android异步更新UI的方式之使用Handler消息传递机制

由于性能要求,android要求只能在UI线程中更新UI,要想在其他线程中更新UI,给大家介绍一种方式:使用Handler消息传递机制. 下面用这种方式更新一个TextView: package com.example.runonuithreadtest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.TextView; public