Handler机制是Android中非常重要的一种消息处理机制,为什么会有handler机制?handler机制是怎样的一种工作流程及如何使用handler机制,本篇文章将对handler机制进行具体的阐述。
一、 Handler机制出现的原因
Android应用程序启动时,系统会创建一个主线程,负责与UI组件(widget、view)进行交互,比如控制UI界面界面显示、更新等;分发事件给UI界面处理,比如按键事件、触摸事件、屏幕绘图事件等,因此,Android主线程也称为UI线程。
由此可知,UI线程只能处理一些简单的、短暂的操作,如果要执行繁重的任务或者耗时很长的操作,比如访问网络、数据库、下载等,这种单线程模型会导致线程运行性能大大降低,甚至阻塞UI线程,如果被阻塞超过5秒,系统会提示应用程序无相应对话框,缩写为ANR,导致退出整个应用程序或者短暂杀死应用程序。
除此之外,单线程模型的UI主线程也是不安全的,会造成不可确定的结果。线程不安全简单理解为:多线程访问资源时,有可能出现多个线程先后更改数据造成数据不一致。比如,A工作线程(也称为子线程)访问某个公共UI资源,B工作线程在某个时候也访问了该公共资源,当B线程正访问时,公共资源的属性已经被A改变了,这样B得到的结果不是所需要的的,造成了数据不一致的混乱情况。
线程安全简单理解为:当一个线程访问功能资源时,对该资源进程了保护,比如加了锁机制,当前线程在没有访问结束释放锁之前,其他线程只能等待直到释放锁才能访问,这样的线程就是安全的。基于以上原因,Android的单线程模型必须遵守两个规则:
1. 不要阻塞UI线程;
2. 不要在UI线程之外访问UI组件,即不能在子线程访问UI组件,只能在UI线程访问。
因此,Android系统将大部分耗时、繁重任务交给子线程完成,不会在主线程中完成,解决了第一个难题;同时,Android只允许主线程更新UI界面,子线程处理后的结果无法和主线程交互,即无法直接访问主线程,这就要用到Handler机制来解决此问题。基于Handler机制,在子线程先获得Handler对象,该对象将数据发送到主线程消息队列,主线程通过Loop循环获取消息交给Handler处理。
二、 Handler机制工作的原理
想要搞明白Handler机制,首先我们要知道几个概念:
1. Message
消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
2. Message Queue
消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
3. Handler
Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
4. Looper
循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。
5. 线程
UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。
当应用程序需要做耗时操作时,不能在主线程中进行,这是就需要开启子线程来处理耗时操作,子线程运行期间如果需要更改UI,但是更改UI的操作只能主线程来做,那么就需要使用Handler机制来处理,消息处理的流程如下:
子线程将需要处理的操作和数据封装成Message(消息)对象。
在子线程里用handler将消息发送到主线程,系统会将Message对象添加到MessageQueue(消息队列)中。
Looper(轮询器)对消息队列不停的轮询,当发现有消息时就交给handler进行处理。
在handler的handleMessage(Message msg)方法中来处理消息。
三、 Handler机制应用案例:点名程序
案例需求:
当点击开始按钮,在手机屏幕中间快速的随机的生成一个名字,当点击停止,随机生成名字操作完成。
案例代码:
1. 布局非常简单,这里不再贴出
2. java代码如下:
代码清单
public class MainActivity extends Activity implements OnClickListener {
protected static final int SUCCESS = 1;
Button btStart,btStop;
TextView tvName;
boolean flag;
String[] names = {"包浩然","李文波","王健","程凯旋","石林","潘岩","王秀","李清振","王剑","周万里","丁一","王瀚","张胜利","崔宁","陶良军","张红杰"
,"楚海鹏","李阔","黄庆坤","张赫强","苏都毕力格","刘晨","李孟","李宁","伍云贵","何邦哲"
,"冯英豪","涂智","唐云川","孟亚楠","田子豪","谢荣雄","贾鑫","脱瑞鹏" };
Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case SUCCESS:
String name = (String) msg.obj;
tvName.setText(name);
break;
default:
tvName.setText("名字有误!");
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btStart = (Button) findViewById(R.id.bt_start);
btStop = (Button) findViewById(R.id.bt_stop);
tvName = (TextView) findViewById(R.id.tv_name);
btStart.setOnClickListener(this);
btStop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_start:
flag = true;
new Thread(){
public void run() {
while (flag) {
Random random = new Random();
int index = random.nextInt(names.length);
Message msg =Message.obtain();
msg.what = SUCCESS;
msg.obj = names[index];
handler.sendMessage(msg);
}
};
}.start();
break;
case R.id.bt_stop:
flag = false;
break;
}
}
}
热点新闻