解析Android的 消息传递机制Handler
1. 什么是Handler:
Handler 网络释义“机械手。经理”意思,在Android它用于管理多个线程UI操作;
2. 为什么会出现Handler:
在Android里面的设计机制。只同意主线程(动时所移动的线程,由于此线程主要是完毕对UI相关事件的处理,所以也称UI线程)
对UI进行改动等操作,这是一种规则的简化,之所以这样简化是由于Android的UI操作时线程不安全的。为了避免多个线程同一时候操作UI造成线程安全
问题,才出现了这个简化的规则。
由此以来,问题就出现了,由于仅仅同意主线程改动UI,那么假设新线程的操作须要改动原来的UI该怎样进行的?举个常见的样例就是:假设新线程的操作是更新UI中TextView
的值。那么该怎样操作?
这时候就须要Handler在新线程和主线程(UI线程)之间传递歇息;
3. Handler的功能:
主要就是两个:
1)在新启动的线程中发送消息;
2)在主线程中获取,处理消息;
看似简单。可是怎样处理同步问题却是一个难题。即怎样把握新线程发送消息的时机和主线程处理消息的时机。这个问题的解决方式是:
在主线程和新线程之间使用一个叫做MessageQueue的队列,新启动的线程发送消息时将消息先发送到与之关联的MessageQueue,然后主线程的Handler方法会被调用
从MessageQueue中去取对应的消息进行处理。
4. Handler的实现机制
Handler的实现主要是依靠以下的几个方法:
读取消息使用到的方法是;
void handleMessage(Message msg) 。进程通过重写这种方法来处理消息。
final boolean hasMessage(int what), 检查消息队列中是否包括what属性为指定值的消息。
final boolean hasMessage(int what,Object object),减产队列中是否有指定值和指定对象的消息。
Message obtainMessage(): 获取消息,课被多种方式重载。
发送消息用到的方法有:
sendEmptyMessage(int what): 发送空消息;
final boolean sendEmptyMessageDelayed(int what, long delayMillis):指定多少毫秒之后发送空消息
final boolean sendMessage(Message msg):马上发送消息
final boolean sendMessageDelayed(Message msg, long delayMillis)指定多少毫秒之后发送空消息
public class HandlerTest extends Activity
{
ImageView show;
// 代表从网络下载得到的图片
Bitmap bitmap;
Handler handler = new Handler()
{
@Override
<span style="color:#ff0000;">public void handleMessage(Message msg)</span>
{
if(msg.what == 0x123) //假设该消息是本程序发的
{
// 使用ImageView显示该图片
show.setImageBitmap(bitmap);
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
show = (ImageView) findViewById(R.id.show);
<span style="color:#ff0000;">new Thread()</span>
{
public void run()
{
try
{
// 定义一个URL对象
URL url = new URL("http://img001.21cnimg.com/photos"+
<span style="white-space:pre"> </span>"/album/20140626/o/C164BDB0B24F59929C2113C0A9910636.jpeg");
// 打开该URL相应的资源的输入流
InputStream is = url.openStream();
// 从InputStream中解析出图片
bitmap = BitmapFactory.decodeStream(is);
// 发送消息、通知UI组件显示该图片
<span style="color:#ff0000;">handler.sendEmptyMessage(0x123);</span>
is.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.start();
}
}
新的进程在将图片从网上解析下来之后向主进程发送空消息,之后主线程中handleMessage()的方法会被自己主动调用,更新UI。
5. 深入理解Handler的工作机制
上面我们看到了一个简单的Handler的工作过程。当中Handler是在主线程中定义的。假设Handler是在子线程中定义的那么能够更深入的理解他的工作原理。
由于有的时候我们须要将主线程中的消息传递给子线程。让子线程去处理一些计算量比較大的任务。由于应用程序应尽量避免在UI线程中运行耗时操作,否则会
导致ANR异常(Application Not Responding)。这种话,我们上面所讲的 主线程和新线程的角色就发生了颠倒,主线程须要向新线程发送消息,然后新线程
进行消息的处理。在这样的情况下,Handler须要定义在新线程中,在这样的情况下须要做一些额外的工作。
我们先来解释一下配合Handler的其他组件:
Looper: 每一个线程相应一个looper,它负责管理MessageQueue。将消息从队列中取出交给Handler进行处理。
MessageQueue:负责管理Message,接收Handler发送过来的message;
下图是整个工作的流程:
以下我们详细阐述一下工作的过程:
在创建一个Handler之前须要先创建Looper,创建的方式是Looper.prepare();
在创建Looper的同一时候会自己主动创建MessageQueue;
以下 创建一个Handler的对象
然后调用Looper的loop()方法
以下的这段代码是一个实例,摘自 疯狂android讲义。主进程将上限发送给子线程计算2-上限之间的素数
public class CalPrime extends Activity
{
static final String UPPER_NUM = "upper";
EditText etNum;
CalThread calThread;
// 定义一个线程类
class CalThread extends Thread
{
<span style="color:#cc0000;">public Handler mHandler;</span> public void run()
{
<span style="color:#ff0000;">Looper.prepare();</span>
<span style="color:#ff0000;">mHandler = new Handler()</span>
{
// 定义处理消息的方法
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
int upper = msg.getData().getInt(UPPER_NUM);
List<Integer> nums = new ArrayList<Integer>();
// 计算从2開始、到upper的全部质数
outer:
for (int i = 2 ; i <= upper ; i++)
{
// 用i处于从2開始、到i的平方根的全部数
for (int j = 2 ; j <= Math.sqrt(i) ; j++)
{
// 假设能够整除,表明这个数不是质数
if(i != 2 && i % j == 0)
{
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的全部质数
Toast.makeText(CalPrime.this , nums.toString()
, Toast.LENGTH_LONG).show();
}
}
};
<span style="color:#ff0000;">Looper.loop();</span>
}
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etNum = (EditText)findViewById(R.id.etNum);
<span style="color:#ff0000;">calThread = new CalThread();</span>
// 启动新线程
<span style="color:#ff0000;">calThread.start();</span>
}
// 为button的点击事件提供事件处理函数
public void cal(View source)
{
// 创建消息
<span style="color:#ff0000;">Message msg = new Message();</span>
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM ,
Integer.parseInt(etNum.getText().toString()));
<span style="color:#ff0000;">msg.setData(bundle);</span>
// 向新线程中的Handler发送消息
<span style="color:#ff0000;">calThread.mHandler.sendMessage(msg);</span>
}
}
版权声明:本文博客原创文章,博客,未经同意,不得转载。
解析Android的 消息传递机制Handler的更多相关文章
- Android异步消息传递机制源码分析
1.Android异步消息传递机制有以下两个方式:(异步消息传递来解决线程通信问题) handler 和 AsyncTask 2.handler官方解释的用途: 1).定时任务:通过handler.p ...
- Android之消息机制Handler,Looper,Message解析
PS:由于感冒原因,本篇写的有点没有主干,大家凑合看吧.. 学习内容: 1.MessageQueue,Looper,MessageQueue的作用. 2.子线程向主线程中发送消息 3.主线程向子线程中 ...
- Handler消息传递机制——Handler类简洁
Handler类的主要作用有两个: 在新启动的线程中发送消息. 在主线程中获取.处理消息. 上面的说法很简单,只要分成两步即可:在新启动的线程中发送消息:然后在主线程上获取.并处理消息.但这个过程涉及 ...
- Handler消息传递机制——Handler、Loop、MessageQueue的工作原理
为了更好地理解Handler的工作原理,先介绍一下与Handler一起工作的几个组件. Message:Handler接收和处理的消息对象. Looper:每个线程只能拥有一个Looper.它的loo ...
- Android Touch消息传递机制探究分析
在Android中,消息的传递控制主要是通过两个方法共同配合使用来对用户的触摸消息进行分发的,下面就来看看这两个方法: onInterceptTouchEvent:此方法定义于ViewGroup中,顾 ...
- 事件处理机制与Handler消息传递机制
一.基于监听的事件处理机制 基于监听的时间处理机制模型: 事件监听机制中由事件源,事件,事件监听器三类对象组成 处理流程如下: Step 1:为某个事件源(组件)设置一个监听器,用于监听用户操作 St ...
- Handler Looper源码解析(Android消息传递机制)
Android的Handler类应该是常用到的,多用于线程间的通信,以及子线程发送消息通知UI线程刷新View等等.这里我主要总结下我对整个消息传递机制,包括Handler,Looper,Messag ...
- Android消息传递之Handler消息机制
前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不 ...
- Android学习之Handler消息传递机制
Android只允许UI线程修改Activity里的UI组件.当Android程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户 ...
随机推荐
- 5、linux下应用字符串相关调用函数列举说明
1.函数原型int strcmp(const char *s1,const char *s2);设这两个字符串为s1,s2,规则当s1<s2时,返回为负数当s1=s2时,返回值= 0当s1> ...
- Vue.js如何划分组件
常见的一些页面,大家坐在一起敲代码就可以了,做完这个页面再做别的页面,但是作为一个功能复杂的系统,尤其是使用一些适合模块化开发的框架,这样会显得效率很低,那么我们就单纯的看在Vue里面如何划分组件的. ...
- jsp页面无法解析EL表达式问题
Servlet版本的问题.原来Servlet中可以设定是否解析EL表达式,只有2.4版本的Servlet默认是解析EL表达式的,而其他版本是默认不解析EL表达式.于是把web.xml中使用的2.5版本 ...
- Android 获取签名证书的具体信息(Eclipse和Android studio通用)
今天要用到签名证书的MD5,可是这个仅仅有在第一次生成的时候我看到了,这可怎么办呢,幸亏我们有google,我们执行以下的命令就OK了. keytool -list -v -keystore 签名证书 ...
- 【心情】codeforces涨分啦!
虽然只有10分. 第二次比赛!
- hreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
阅读更多 工作中多处接触到了ThreadPoolExecutor.趁着现在还算空,学习总结一下. 前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍Th ...
- [Ramda] Declaratively Map Data Transformations to Object Properties Using Ramda evolve
We don't always control the data we need in our applications, and that means we often find ourselves ...
- ios开发总结:Utils常用方法等收集,添加扩展类,工具类方法,拥有很多方便快捷功能(不断更新中。。。)
BOBUtils 工具大全 本人github开源和收集功能地址:https://github.com/niexiaobo [对ios新手或者工作一年以内开发人员很有用处] 常用方法等收集.添加扩展类. ...
- jquery pagination分页的两种实现方式
原文链接:http://blog.csdn.net/qq_37936542/article/details/79457012 此插件是jQuery的ajax分页插件.如果你用到此插件作分页的时候,涉及 ...
- ArcGIS网络概述
转载自原文 ArcGIS网络概述 一.地理网络 (一)基本概念 由一系列相互连通的点和线组成,用来描述地理要素(资源)的流动情况. (二)网络类型 1.定向网络 (1)流向由源(source)至汇(s ...