Handler的作用
- 实现异步的消息处理
- 接收消息,调度消息,派发消息,处理消息
- 线程间的通信
最常用的用法,就是子线程不能更新UI,需要通过handler,把消息发送到主线程进行更新。
比如这样
private TextView mTextView;
private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText((String) msg.obj);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView=findViewById(R.id.test);
new Thread(new Runnable() {
@Override
public void run() {
Message message= Message.obtain();
message.obj="handler";
mHandler.sendMessage(message);
}
}).start();
}
mHandler.sendMessage(Message.obtain());干了什么?
代码追踪一下
//1 其实调用了sendMessageDelayed,只是第二个参数为0
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
// 2
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
//当前系统时间+延迟时间。
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
// 3
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//消息队列 mQueue是在构造函数中经行了赋值,是主线程中的looper对象中的MessageQueue
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);
}
// 4
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把Handler对象赋值给了MessageQueue的target属性
msg.target = this;
//这里默认的构造方法,传的是false。此处不成立。
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
调用流程是这样的,sendMessageDelayed–>sendMessageAtTime –> enqueueMessage –> MessageQueue的enqueueMessage方法。
也就是说,我们在子线程发送通过handler.sendMessage,其实就是往MessageQueue中插入了一条消息,以及时间when(SystemClock.uptimeMillis(),表示是系统开机到当前时间的总数),然后MessageQueue会把这条消息进行排队。
其实,我们调用Handler.sendxxx方法,其实只是单纯的往队列里添加消息,但是,它是怎么在主线程中调用handler的handleMessage方法?
看前面Looper的分析。
public static void loop(){
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
//如果msg为null,跳出死循环
return;
}
...
try {
//调用的就是handler的dispatchMessage(msg)-->handleMessage
msg.target.dispatchMessage(msg);
}
...
//消息回收
msg.recycleUnchecked();
}
}
在ActivityThread的main()方法中,调用了
Looper.prepareMainLooper();
...
Looper.loop();
说明系统其实已经帮我们在主线程,配置好了Handler。Looper会从一启动就开始无限循环,而且主线程的Looper的MessageQueue又无法出队,会一直等着handler发送的消息,从而形成一个完整的线程通讯的过程。
这里,又引出一个问题,在子线程new handler()会怎么样?
new Thread(new Runnable() {
@Override
public void run() {
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
}
}).start();
会报错,异常是:Can’t create handler inside thread that has not called Looper.prepare()。
我们看构造方法
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
...
}
创建handler的时候,会检查当前线程的Looper对象(一个线程通过ThreadLocal绑定一个Looper对象,不清楚的可以看看前面的文章),很明显,我们并没用初始化当前子线程的Looper对象,自然会报错。
解决方法跟ActivityThread的main方法一样。
new Thread(){
@Override
public void run() {
super.run();
//1、初始化looper
Looper.prepare();
//2、new Handler
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//可以接收来自其他线程的消息--如子线程
}
};
//3、循环
Looper.loop();
throw new RuntimeException(" thread loop unexpectedly exited");
}
}.start();
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(Message.obtain());
}
});
源码部分
1、构造方法
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这几个构造方法,大致就那么几个变量,Looper,Callback,boolean async。
- 通常用到的空参构造器,默认获取的是当前线程的Looper,如果Looper为null抛异常。
- 传入Callback的构造器,消息的处理,则会通过callback来处理,代替handleMessage。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
传入一个boolean类型的async,如果true,则调用msg.setAsynchronous(true),代表消息是异步的,默认是同步的(异步消息其实是这样的,我们可以通过enqueueBarrier往消息队列中插入一个Barrier,那么队列中执行时间在这个Barrier以后的同步消息都会被这个Barrier拦截住无法执行,直到我们调用removeBarrier移除了这个Barrier,而异步消息则没有影响,消息默认就是同步消息)。
传入一个Looper对象,则会用到当前线程的MessageQueue,可以用来在子线程接收信息。前面的代码,可以改为传入Looper对象。
一系列方法
- dispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public interface Callback {
public boolean handleMessage(Message msg);
}
这里,有两个判断,我们通常只会用到handleMessage这个方法,来执行message。
第一,当message本身设置了callback,则会调用message本身的callback方法。
第二,当我们在构造器时,传入了CallBack,则调用mCallback.handleMessage(msg),消息处理了返回true,然后return,否则才会调用handlerMessage。
- obtainMessage系列
这系列方法就是调用Message.obtain()方法,让Message的性能更高。
- post系列方法
这系列方法,主要是给一个Runnable赋值给Message中,最终执行该Runnable的run方法。