说到Handler想必大家都不陌生!Android中主要的消息机制也就体现在Handler上,在日常开发中最常见的操作就是通过Handler更新UI(子线程是不允许更新UI的)。
简要概括一下Handler机制
- Handler在初始化过程中和Looper进行绑定,确切来说是为了和MessageQueue 进行绑定,有了MessageQueue消息队列就可以通过sendMessage等方法将Message对象加入到消息队列中
- Looper通过loop方法进入到无限循环状态,有消息就处理最终回调到我们复写的方法handleMessage,无消息则进入阻塞等待。
- Activity在创建的过程中会创建出Looper对象,所以在Activity中不要求创建Looper,但是如果新建子线程需要使用到Handler的话就需要通过Looper的prepare()方法创建出looper对象 。
- 一个线程中只允许出现一个Looper对象,在Looper构造体中还会创建MessageQueue,这也间接保证MessageQueue对象的唯一。
Handler的原理如果还不是很了解的话可参考hongyang大神blog:
http://blog.csdn.net/lmj623565791/article/details/38377229
既然hongyang大神都对Handler已经总结那么好了,此处就不在多说些什么。本文是罗列出几个Handler知识点以及Android源码中究竟那些类使用到了Handler,你要是把这些相关知识也给面试官说一遍,那面试官在Handler这一块就真的没什么可问的了,(^__^) 嘻嘻……
Handler小知识点
- 同一个线程中可以new出多个Handler吗?使用多个Handler各自发送消息会不会混乱?
- Looper通过loop方法进入无限循环处理消息,那为什么主线程不会卡住呢?
第一个问题
首先肯定是允许new出多个Handler对象的,消息处理也不会混乱,哪个Handler发送的消息最终还是会交给它的handleMessage方法处理。怎么做到的呢?我们来看一下android源码
//Handler class
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//将Handler对象放入Message
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//Looper class
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);//Handler中的类我们已经知道msg.target指向Handler对象。
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...//省去部分代码
}
}
ok!Handler有很多发送消息的方法,最终都会调用sendMessageAtTime这个方法,方法中通过执行enqueueMessage方法将Message加入到MessageQueue中,看一下14行 msg.target = this; 这是什么?原来Message对象有target属性专门保存发送该消息的Handler对象,再看一下32行,Looper的loop方法中有 msg.target.dispatchMessage(msg);我们知道这个方法最终会回调到HandleMessage方法,msg.target 就是发送该消息的handler,这就一下子明白了,哪个Handler发送的Message最终还由它自己进行处理!
第二个问题
这个问题,我并不打算在陈述,请参考http://www.jianshu.com/p/72c44d567640 作者已经说了很明白。
以下是引用作者的总结:
主线程确实是阻塞的,不阻塞那APP怎么能一直运行,只不过是没有弄明白既然阻塞了,为什么还能调用各种声明周期而已.调用生命周期是因为有Looper,有MessageQueue,还有沟通的桥梁Handler,通过IPC机制调用Handler发送各种消息,保存到MessageQueue中,然后在主线程中的Looper提取了消息,并在主线程中调用Handler的方法去处理消息.最终完成各种声明周期.
Android使用到Handler的类
- HandlerThread
- IntentService
AsyncTask
HandlerThread
以往在子线程中创建Handler我们会做如下操作:
class MyThread extends Thread {
Handler mHandler;
@Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
public void stopLoop() {
Looper.myLooper().quit();
}
}
6 7 13 17行这些代码是必须的。如果每次这样做岂不是很麻烦,所以android 给我们提供了HandlerThread 看一下源码
//HandlerThread class
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
//handler 初始化传递Looper对象参数,可使用此方法获取
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
//停止Loop的无限循环,也就意味着线程结束
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
看上面的HandlerThread方法和我们自己写的如出一辙,HandlerThread 优势在于帮我们创建了Thread和Loop对象,我们仅需要初始化Handler,如下是使用方法:
//我是在Activity的onCreate()方法书写的
HandlerThread handlerThread = new HandlerThread("thread");
handlerThread.start();
Handler mHandler = new Handler(handlerThread.getLooper());
Note : 线程是异步的,start开始之后就会回调run方法,那么HandlerThread的run()方法已经和Handler的初始化异步了,怎么保证Handler初始化一定能拿到Looper对象?看源码中run(),和getHandler()中wait和notifyAll是不是一下子就明白了,JAVA加锁机制。
IntentService
服务主要作用就是提高运行权限等级在后台进行耗时操作,而我们又知道Service是在主线程上运行的所以一般在进行耗时操作需要自己创建出线程,将耗时操作交给子线程去做。IntentService是一个抽象类继承Service,我们需要复写onHandleIntent方法,如下是相关源码:
//IntentService class
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//Handler将回调消息,再次传给onHandleIntent
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
protected abstract void onHandleIntent(@Nullable Intent intent);
Service的生命周期第一次启动执行onCreate()—-onStart(),再次启动则直接执行onStart()。onCreate()作为入口那么我们先看一下这部分代码,初始化HandlerThread然后通过HandlerThread获取Loop对象创建Handler对象,这没什么,然后在看一下onStart()方法,onStart所做的事情就是通过Handler不断的发送消息。然后消息最终会毁掉给我们复写的onHandleIntent。
通过上面我们知道当我们多次startService(Intent intent),intent都会被包装到Message加入到消息队列中等待顺序执行。
使用IntentService具有以下优势:
- 无需在Service中创建子线程
- 当所有的任务执行完毕,Service会执行stopSelf方法,自动destory服务
AsyncTask
AsyncTask 请参考上一篇博客:http://blog.csdn.net/wning1/article/details/72852892 就明白AsyncTask 中Handler的运用了。
ok! 今天就记录到这。