Handler学习总结
讲解handler之前,我们要认识到这一点:在activity创建时候,系统会给我们创建一个activity main thread ,这也就是我们所说的UI线程或者Main线程。
-
要学习handler,就得了解几个重要的关系。
- Handler:接收和发送消息,更新UI操作
- Looper:负责接收Handler发送的消息,将消息存放在MessageQueue里面,通过Looper.loop()轮询取出消息。
- Message:Handler发送消息的内容,存放在message里面。
- MessageQueue:存储消息的容器,类似一个消息栈。
Handler的几个用法:
//handler.post 立即发送消息
handler.post(new Runnable() {
@Override
public void run() {
}
});
//handler.postDelayed 延迟时间发送消息
handler.postDelayed(new Runnable() {
@Override
public void run() {
}
},0);
//handler.send 立即发送消息
handler.sendEmptyMessage(0);
//handler.sendMessageDelayed 延时发送消息
handler.sendMessageDelayed(new Message(),0);
还要清楚这样一点,Handler发送的消息都是要自己接收的,发送到looper的消息通过looper.loop()方法从messageQueue取出message之后,通过Handler里面的handleMessage()这个方法来获取消息。
创建一个handler,如果没有说明具体绑定looper,那就是绑定在UI线程的Looper上的。我们可以看一下源码
在new 一个Handler时候:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
然后看看this的方法:
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;
}
看到有一行是 mLooper = Looper.myLooper();说明Handler是绑定在Looper.myLooper(),也就是Ui线程上的。
如果我们开一个子线程,给Handler创建的时候给它一个looper对象
final HandlerThread handlerThread = new HandlerThread("ChildThread");
handlerThread.start();
childHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.e("Child_Thread------>",String.valueOf(childHandler.getLooper().getThread()));
handler.sendEmptyMessageDelayed(0, 1000);
}
};
先写一个子线程HandlerThread,然后获取handlerThread的looper来创建一个子线程的Handler,然后跟主线程的Handler相互通信。
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.e("UI_Thread------>", String.valueOf(handler.getLooper().getThread()));
childHandler.sendEmptyMessageDelayed(0, 1000);
}
};
查看打印的日志就会发现线程名称是不一样的,一个是Mian线程,一个是我们自己定义的ChildThread线程。
这里解释一下为啥要用HandlerThread创建线程呢,我们来看一下源码:
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;
}
在获取handlerThread.getLooper()时候发现,如果Looper是空的,需要等待,等待创建完Looper之后,在返回创建好的Looper。这样或许还显示不出来HandlerThread的好处,我们举个这样的例子:
首先自定义一个子线程:
class MyThread extends Thread {
private Handler childHandler;
public Looper looper;
@Override
public void run() {
Looper.prepare();
looper = Looper.myLooper();
childHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
}
};
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Looper.loop();
}
}
然后让子线程暂停一秒模拟线程并发的情况。
然后调用子线程,把子线程的looper绑定到Handler中
MyThread thread = new MyThread();
thread.start();
Handler handler = new Handler(thread.looper) {
@Override
public void handleMessage(Message msg) {
}
};
handler.sendEmptyMessage(0);
运行程序,会发现有一个NullPointerException: Attempt to read from field ‘android.os.MessageQueue android.os.Looper.mQueue’ on a null object reference的异常,说明在创建Handler时候,Looper是个空的,所以这里在防止线程并发时候,就需要引入HandlerThread这个类。