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);}}};@Overridepublic 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>{// 定义处理消息的方法@Overridepublic 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>}}@Overridepublic 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>}// 为按钮的点击事件提供事件处理函数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>}}

更多相关文章

  1. Android(安卓)4.0 触摸屏消息(二大写的二)
  2. Android中的线程处理
  3. Android线程模型解析(包括UI的更新)
  4. Android中AsyncTask(异步任务)和Handler(线程消息机制)的详解
  5. Android,谁动了我的内存(1)
  6. android开发——通过子线程更新界面UI
  7. Android应用程序线程消息循环模型分析
  8. Handler完全重新理解
  9. Android线程模型

随机推荐

  1. 详解 Android(安卓)的 Activity 组件
  2. 不用SDK manager 下载 Android(安卓)sdk
  3. Android(安卓)GPS架构分析
  4. android 登陆、注册、并个指定用户充值
  5. Android(安卓)LaunchMode and StartActiv
  6. android adb配置环境变量
  7. 上官网学android之二(Building your First
  8. Ted Mosby - 一个MVP框架的软件架构
  9. Android(安卓)ADB server didn't ACK * f
  10. Android(安卓)ID