一些基础:
handler主要用于在子线程中经行耗时操作避免阻塞UI线程再把消息发送到UI线程再经行处理,handler机制中海包括了Looper,MessageQueue,ThreadLocal等。
Looper:
handler一般的写法为:
private Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
//在这里即可以做一些UI操作了。。。
}
};
new Thread(new Runnable() {
@Override
public void run() {
//开启一个线程这里做一些耗时操作
Message message = Message.obtain();
// message.setData(...);
// message.what=...
handler.sendMessage(message);
}
}).start();
这样就实现了在子线程中经行耗时操作,把结果通过handler、message发送到UI线程中再做处理,在我们平常使用中一般不需要去声明一个looper或者messageQueue因为一般我们的handler都是写在主线程中的,Android的入口是ActivityThread的main方法在那里面已经帮我们声明好了一个looper。当然我们的handler声明在一个子线程的话则必须显示的声明一个Looper 比如:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();//获取当前线程的looper
Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
}
};
Message message = Message.obtain();
handler.sendMessage(message);
Looper.loop();//looper开始处理消息
}
}).start();
这里出现了两个方法Looper.prepare()和Looper.loop()两个方法,下面是Looper.prepare方法的源码:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//通过sThreadLocal.get()去判断要是拿到的looper对象不为空的话则抛出异常
//因为一个线程中只能有一个looper,这里后面再讨论
//当取到的looper对象为空会会调用方法 new Looper(quitAllowed)
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//这里又声明了一个MessageQueue对象,这样就保证了一个线程一个looper一个MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
下面是loop()方法的部分源码:
public static void loop() {
//mylooper()方法就一段代码sThreadLocal.get();
//sThreadLocal.get();返回了之前set进去的looper
final Looper me = myLooper();
.......
//拿到了looper就拿到了对应的MessageQueue。
final MessageQueue queue = me.mQueue;
//一直循环的取messageQueue中的message对象
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
//通过这句代码把取出的message对象转发到了handler中
//这里的target其实就是handler后面会再分析
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
}
}
handler:
在之前的代码中看到new Handler中传入了Looper.myLooper()
public static @Nullable Looper myLooper() {
//这里就返回了之前set进去的looper对象
return sThreadLocal.get();
}
//构造方法
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
//this(looper, null, false);会调用这里的方法
//在这里不仅初始化了mLooper,还通过looper拿到了对应的MessageQueue对象
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
在handler中用个sendMessage方法点进源码查看会一路调用各种sendMesage。。。最后会来到sendMessageAtTime方法
//这里的msg就是我们在外部发送的那个message对象
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//这里就和之前looper.loop()方法对应上了,target就是handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//把这个msg压入messageQueue中通过looper.loop取获取再经行处理
return queue.enqueueMessage(msg, uptimeMillis);
}
现在知道之前的looper.loop()方法最终会调用到handler.dispatchMessage(msg)方法
public void dispatchMessage(@NonNull Message msg) {
//msg.callback这个属性是runnable,是handler.post方法用的
//我们之前的写法没有去设置这个属性所以它是个null所以会执行
//handleMessage这个方法,而这个方法就是我们在外部重写的方法
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//这就是平时最简单的handler的post写法
new Handler(Looper.myLooper()).postDelayed(new Runnable() {
@Override
public void run() {
}
},300);
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
//其实跟sendMessage方法差不不大,通过getPostMessage(r)把Runnable封装成一个message对象
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
//这里就对message对象的callback属性进行了赋值,这样在dispatchMessage方法中
//就不会走handleMessage方法了而是handleCallback(msg);方法
m.callback = r;
return m;
}
handler.post方法和sendMessage方法基本一样,post更简单它时候只对一件事情处理的时候用,message有setData和what等方法适合对复杂的事情做处理。
最后至于handler到底是怎样实现线程切换的实际上只是因为线程间资源共享,我们的handler声明在主线程,对应的looper、messageQueue都在主线程,所以发出的消息最终就是在主线程中处理