Handler是什么
Handler是Android提供的用来更新UI的一套机制, 也是一套消息处理机制,我们可以通过它来发送和处理消息。
Handler在Android Framework中应用也非常广泛: 其中,Activity生命周期回调的方法被调用的过程就是通过Handler来实现的。
为什么要使用Handler
Android设计的时候就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制更新UI界面,会抛出异常错误(非UI线程更新UI)。
另外,关于UI线程和更新UI,官网有如下一段话的解释:
When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler.
当应用启动的时候, 会创建一个进程,进程的主线程运行着消息队列,管理着最高级别的应用对象(例如activity,broadcast receivers 以及其他界面上的内容),这个主线程就是我们常说的UI线程。当我们创建自己的线程的时候,我们想要和主线程进行通信,就必须通过Handler来实现。
Handler 基本用法
官网的解释:
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
翻译不太通顺,直接用代码来解释一下吧:
1, Handler提供了以下方法:
post(Runnable) [postAtTime(Runnable, long)](https://developer.android.com/reference/android/os/Handler.html#postAtTime(java.lang.Runnable, long)) [postDelayed(Runnable, long)](https://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable, long)) sendEmptyMessage(int) sendMessage(Message) [sendMessageAtTime(Message, long)](https://developer.android.com/reference/android/os/Handler.html#sendMessageAtTime(android.os.Message, long)) [sendMessageDelayed(Message, long)](https://developer.android.com/reference/android/os/Handler.html#sendMessageDelayed(android.os.Message, long))
其中post Runnable 是将Runnable发送给其他线程(创建handler的线程)执行;
send message一类的方法则是发送消息, 与下面的handleMessage相对应:
2, 重写Handler的handleMessage方法,可以通过message类型判断执行条件,而handleMessage的执行是在其他线程中,可以做UI更新的操作。
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
...//更新UI
}
};
实例
下面是一个通过Handler实现TextView控件读秒操作的例子, 在App的首页广告闪屏中很常见,直接上代码:
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//计时
int msgId = msg.what;
if(msgId == MSG_ID_COUNT){
int count = getCount();
ignoreBtn.setText("跳过 " + count);
if(count > 0){
mHandler.sendEmptyMessageDelayed(MSG_ID_COUNT, 1000);
}
}else if(msg.what == MSG_ID_IGNORE){
launchApp();
}else if(msg.what == MSG_ID_NOAD){
launchApp();
}
}
};
private int getCount(){
mCount--;
if(mCount <= 0){
launchApp();
}
return mCount;
}
写了一个Handler,通过重写handleMessage处理3个消息。我们会在程序刚启动的时候,发送一个MSG_ID_COUNT消息,开始首页广告的倒计时:
mHandler.sendEmptyMessageDelayed(MSG_ID_COUNT, 1000);
其中第二个参数表示延时的事件1000ms
当用户点击“跳过”按钮的时候,我们会发送一个MSG_ID_IGNORE消息:
mHandler.sendEmptyMessageDelayed(MSG_ID_IGNORE, 100);
这样,就实现了一个基本的广告跳过的功能。可以看到,Handler实现了2个基本功能:
1, 可以指定消息发送的时间,倒计时功能;
2, 可以在handleMessage方法中更新UI,倒计时界面;
Handler原理
说到Handler的原理,我们先来看看Handler的源码,以下是Handler构造函数:
public Handler() {
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(); // 获取Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 获取消息队列
mCallback = null;
}
上述注释的两行代码,可以看到有两个概念: **Looper, MessageQueue **
首先说说这两个概念:
- Looper, 包含一个消息队列MessageQueue, 作为消息封装的载体。
主要方法: Looper.looper() , 一个死循环方法, 不断地查看MessageQueue中是否有新的消息; - MessageQueue, 一个消息队列, 可以添加消息,处理消息;
那么,在Handler的构造方法中,获取了Looper和MessageQueue并保存为全局变量,是为了与Handler进行关联。
下面是一张简明的图,很好的阐述了Handler, Looper, MessageQueue三者之间的关系:
关系,来自stackoverflow
总结: Handler负责发送消息, Looper负责接收Handler发送的消息,并直接把消息传回Handler自己,后续就会调用回调等方法(handleMessage)来处理。
为什么要设计Handler更新UI
上面的关系图,我们可以看到,如果想更新UI, 通过Handler的sendMessage方法发送消息, 然后作为UI Thread的Looper会轮询消息队列MessageQueue, 从而保证了多线程下UI更新的正确性。也就是说,如果没有Handler机制,在多线程下更新UI,我们必须使用锁来保护避免并发的问题。
update 来自《Android开发艺术》
Android中的UI并不是线程安全的, 如果在多线程下访问UI,则会导致UI界面状态不可控制的情况; 而如果加上锁的机制,有两个缺点:1, 将UI访问的逻辑变的非常复杂; 2, 会导致访问UI的效率变低。
所以,基于这两个缺点,在多线程中操作UI,就提供了Handler机制。
参考资料:
慕课网 Handler详解
Handler官网
stackoverflow What is the relationship between Looper, Handler and MessageQueue in Android?
网友评论