在Android中,主要通过MessageQueue、Looper和Handler三个类来实现Android应用程序的消息处理。其中,MessageQueue类用来描述消息队列;Looper类用来创建消息队列,以及进入消息循环;Handler类则用来发送消息和接收消息。
本文将主要对Handler进行简要介绍,并以一个简单的实例演示如何使用Handler实时更新UI。
1.Handler的作用
在Android中,当应用程序启动时,Android系统会启动一个主线程(也被称为UI线程),主要用来管理界面中的UI控件,对用户操作进行实时响应。如果我们在UI线程中进行一项非常耗时的操作,比如点击Button按钮,进行文件上传或下载,那么在这段时间内界面会出现假死现象(不响应用户操作),这显然是用户体验极差的。更为严重的是,如果在5秒内这个耗时的操作还未结束的话,Android系统会进行错误提示“强制关闭”。
所以通常的做法是启动一个子线程,然后在子线程中来完成这些比较耗时的操作。但是,如果我们想要在子线程中更新UI,那又该如何做呢?
因为在Android中,更新UI只可以在主线程中进行,所以想要在子线程中更新UI,就必须得子线程通知主线程,然后主线程来更新UI。
这一过程正是通过Handler来实现的。
子线程可以通过两种方式与Handler进行通信:Message和Runnable。使用Message可以从子线程中传递一些参数给主线程,Handler获取这些信息并进行相应的处理。使用Runnable则可以直接执行某个处理结果。其实,这两者的实质都是在Handler的队列中放入内容,Handler会处理完一个消息或者执行完某个处理之后再进行下一步操作,这样就不会出现多个线程同时要求进行UI处理而引发混乱现象。
2.Handler的常用方法
Handler的消息队列中的内容(Message或Runnable)可以设置为马上执行,延迟一定时间再执行或者指定在某个时刻执行。此外,还可以指定将其放在队列的头部,表示该内容具有最高优先级别,立刻执行。
这些要求的设置可以通过以下一些函数来实现:
(1)post(Runnable r);
(2)postAtTime(Runnable r, long uptimeMillis);
(3)postDelayed(Runnable r, long uptimeMillis);
(4)postAtFrontOfQueue(Runnable r);
(5)sendEmptyMessage(int what);
(6)sendMessage(Message msg);
(7)sendMessageAtTime(Message msg, long uptimeMillis);
(8)sendMessageDelayed(Message msg, long uptimeMillis);
(9)sendMessageAtFrontOfQueue(Runnable r);
3.实例
在本实例中,我们创建了一个Web工程,该Web工程很简单,仅仅是获取系统的当前时间,然后显示出来而已。
在Tomcat上运行该Web工程,能够看到如图1所示的运行效果。
图1 Web工程运行效果
该页面是通过一个简单的date.jsp文件来实现的。
我们现在要做的就是,在Android工程中,通过一个TextView来显示当前页面的内容,并且在子线程中每隔1秒钟,发送一个Message给Handler,Handler收到Message通知后,完成刷新UI的操作。
下面就来说说每一步的具体实现。
3.1在主线程中启动一个子线程
首先,我们需要在主线程中启动一个子线程,这个比较简单,直接在MainActivity的onCreate()方法中调用如下方法即可:
new Thread(mRunnable).start();
3.2在子线程中发送Message给Handler
在创建子线程时,我们使用了Runnable接口对象mRunnable。这里,只需要实现Runnable接口,并重写该接口的run()方法,在run()方法中实现每1秒发送一条Message给Handler即可。具体实现方法如下:
1 /* 2 * Function : 实现run()方法,每1秒发送一条Message给Handler 3 * Author : 博客园-依旧淡然 4 */ 5 private Runnable mRunnable = new Runnable() { 6 public void run() { 7 while(true) { 8 try { 9 Thread.sleep(1000); 10 mHandler.sendMessage(mHandler.obtainMessage()); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 } 15 } 16 };
3.3Handler接收Message通知
最后,我们创建一个Handler对象,用来接收Message通知。在收到Message通知后,完成刷新UI的操作即可。具体实现方法如下:
1 /* 2 * Function : 实现handleMessage()方法,用于接收Message,刷新UI 3 * Author : 博客园-依旧淡然 4 */ 5 private Handler mHandler = new Handler() { 6 public void handleMessage(Message msg) { 7 super.handleMessage(msg); 8 refreshUI(); 9 } 10 };
3.4刷新UI
由以上的代码可以看出,刷新UI的操作,我们是放在refreshUI()方法中来完成的。refreshUI()方法的实现也很简单,调用HttpUtils工具类中的getInputStream()方法,获得图1所示Web工程的页面内容输入流,再将该输入流转化为字符串,放入TextView控件中进行显示即可。具体实现方法如下:
1 /* 2 * Function : 刷新UI 3 * Author : 博客园-依旧淡然 4 */ 5 private void refreshUI() { 6 try { 7 InputStream inputStream = HttpUtils.getInputStream(); 8 String resultData = HttpUtils.getResultData(inputStream); 9 mTextView.setText(resultData); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 }
3.5实例效果
最后,运行该Android工程,运行效果如图2所示,可以看到,当前时间每隔1秒会刷新一次,能够始终保持与图1所示页面的时间同步。
图2 运行效果