Handler在Android中有着重要的作用,学习Handler能清晰的理解Android线程消息传递机制。
什么是Handler?
Android官方文档给出的解释是:一个Handler允许你发送和处理Message和与某一线程相关联的Runnable对象。每一个Handler实例都与一个单一的线程和他的消息队列相关联。当你创建了一个新的Handler,这个Handler就绑定到了这个线程或者消息队列,将会分发这个消息和runnable到消息队列中,并在他们出队列的时候执行。
Handler重要有两个应用场景:
1.安排一个消息或者runnable在未来的某个时间点执行
2.在其他线程执行你的方法
消息队列完成的方法包括
1. post(Runnable)
2. postAtTime(Runnable, long)
3. postDelayed(Runnable, long)
4. sendEmptyMessage(int)
5. sendMessage(Message)
6. sendMessageAtTime(Message, long)
7. sendMessageDelayed(Message, long)
这里包含post的允许你传入一个runnable对象进入队列而被消息队列唤起,而sendMessage允许你把一个消息传入队列,这个消息包含绑定的数据,这个消息将会被handlerMessage(Message)所处理。
Handler的应用背景
上面大致讲了一下Handler在官方文档上的描述,下面讲一下Handler的应用背景。
当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程。
Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题。
为了解决Android应用多线程问题—Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值。
Handler更新UI的方法
1.在主线程中声明:
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO 接收消息并且去更新UI线程上的控件内容
if (msg.what == UPDATE) {
// 更新界面上的textview
tv.setText(String.valueOf(msg.obj));
}
super.handleMessage(msg);
}
};
子线程处理完成任务后发送消息到上面:
new Thread() {
@Override
public void run() {
// TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值
try {
//do something
Message msg = new Message();
msg.what = UPDATE;
msg.obj = "更新后的值" ;
handler.sendMessage(msg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
Handler源码分析
Handler中主要有四个构造函数:
1.public Handler()
2.public Handler(Callbackcallback)
3.public Handler(Looperlooper)
4.public Handler(Looperlooper, Callbackcallback)
第1个和第2个构造函数都没有传递Looper,但源码注释中说了(Default constructor associates this handler with the {@link Looper} for the current thread.)就是说这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。
final Looper mLooper;
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
后两个构造方法则将Looper赋值到mlooper中
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这里的Handler消息传递的整体图为:
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
在Android开发中主要的使用方法
1在主线程中定义Handler
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
String data = (String)msg.obj;
updateUI();
textView.setText(data);
break;
default:
break;
}
}
};
private void update() {
new Thread(new Runnable(){
@Override
public void run() {
//耗时操作,完成之后发送消息给Handler,完成UI更新;
//需要数据传递,用下面方法;
Message msg =new Message();
msg.obj = "数据";//可以是基本类型,可以是对象,可以是List、map等;
mHandler.sendMessage(msg);
}
}).start();
}
2 用Activity对象的runOnUiThread方法更新
new Thread() {
public void run() {
//这儿是耗时操作,完成之后更新UI;
runOnUiThread(new Runnable(){
@Override
public void run() {
//更新UI
imageView.setImageBitmap(bitmap);
}
});
}
}.start();
或者
Activity activity = (Activity) imageView.getContext();
activity.runOnUiThread(new Runnable(){
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
3View.post(Runnable r)
imageView.post(new Runnable(){
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});