Looper主要有prepare()和loop()两个方法,Looper是用来从MessageQueue中抽取Message,发送给Handler进行处理。
prepare()方法:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。第一次调用prepare()方法,if条件不成立,所以将创建的Looper对象保存到sThreadLocal中。第二次调用就会抛出异常,说明Looper.prepare()方法不能被调用两次,也保证了一个线程中只有一个Looper实例。
Looper的构造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
在构造方法中,创建了一个MessageQueue(消息队列)
loop()方法中调用myLooper()方法取出sThreadLocal中保存的Looper实例,如果Looper实例为null则抛出异常,所以looper方法必须在prepare方法之后运行。接着会获取到该looper实例中的mQueue(消息队列)。然后进入了无限循环,从消息队列中取出消息。调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理,Msg的target就是handler对象。
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue
public static Looper myLooper() {
return sThreadLocal.get();
}
Handler的构造方法中会调用Looper.myLooper()获取了当前线程保存的Looper实例,然后又通过mLooper.mQueue获取了Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了Handler的sendMessage(Message msg)方法最后调用了sendMessageAtTime(),在此方法内部直接获取MessageQueue然后调用了enqueueMessage方法
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
enqueueMessage方法中msg.target赋值为this,在Looper的loop方法会取出每个msg然后交给msg.target.dispatchMessage(msg)去处理消息,所以当前的handler就是msg的target。最终调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。不断从MessageQueue中读取Handler发来的消息,然后再回调创建这个消息的handler中的dispathMessage方法,在dispatchMessage方法中调用了handleMessage(msg)方法,方法内部是空实现,因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public void handleMessage(Message msg) {
}
注意:在Activity中,我们并没有调用Looper.prepare()和Looper.loop()方法,但是Handler可以成功创建,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法
HandlerThread是Android API提供的一个便捷的类,使用它我们可以快速的创建一个带有Looper的线程,有了Looper这个线程,我们又可以生成Handler。HandlerThread本质上是一个线程类,它继承了Thread;
HandlerThread有自己的内部Looper对象,可以进行looper循环;
通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务。
创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run方法,创建Looper对象
使用普通的Thread来创建一个Handler的过程:
Handler mHandler;
private void createThreadWithHandler() {
new Thread() {
@Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(Looper.myLooper());
Looper.loop();
}
}.start();
}
调用Looper.prepare 创建与当前线程绑定的Looper实例
使用上面创建的Looper生成Handler实例
调用Looper.loop()实现消息循环
HandlerThread使用:
//传入参数的作用主要是标记当前线程的名字,可以任意字符串
HandlerThread workerThread = new HandlerThread("LightTaskThread");
workerThread.start();
mHandler = new Handler(workerThread.getLooper());
注意:上面的workerThread.start()必须要执行。
在activity的onDestory方法中调用workerThread.quit()方法结束当前的Looper循环
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
从源码可以看出HandlerThread继续自Thread,构造函数的传递参数有两个,一个是name指的是线程的名称,一个是priority指的是线程优先级,我们根据需要调用即可。其中成员变量mLooper就是HandlerThread自己持有的Looper对象。onLooperPrepared()该方法是一个空实现,是留给我们必要时可以去重写的,但是注意重写时机是在Looper循环启动前
看看run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
前面我们在HandlerThread的常规使用中分析过,在创建HandlerThread对象后必须调用其start()方法才能进行其他操作,而调用start()方法后相当于启动了线程,也就是run方法将会被调用,而我们从run源码中可以看出其执行了Looper.prepare()代码,这时Looper对象将被创建,当Looper对象被创建后将绑定在当前线程(也就是当前异步线程),这样我们才可以把Looper对象赋值给Handler对象,进而确保Handler对象中的handleMessage方法是在异步线程执行的。
最近看到的一篇详细分析线程池的文章,学习一下:
https://mp.weixin.qq.com/s/rHnzqlzJusIVNO7X7mBDkA