HandlerThread和Handler,Message,Lo
1、HandlerThread
Thread线程是一次性消费品,当Thread线程执行完一个任务之后,线程就会被自动销毁了。如果此时又有一个任务需要执行,就得重新创建一个线程这样多次创建和销毁线程是很耗系统资源的,因此会有性能问题。为了解这个问题,可以构建一个循环线程Looper Thread,当有任务放到该循环线程中时,线程执行任务,执行完之后循环线程处于等待状态,直到下一个新的任务被放进来。这样就避免了多次创建Thread。这个问题可以使用HandlerThread,他的父类是Thread,因此HandlerThread其实是一个线程,只不过内部实现了一个Looper的循环,他依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。
public class HandlerThread extends Thread {
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();//创建与线程关联的Looper对象
//进入同步块,当前线程已经创建myLooper对象成功
//调用notifyAll通知其他阻塞在当前对象上的线程,主要是通知getLooper中的wait
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();//启动loop
mTid = -1;
}
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 {// 直到mLooper创建成功,才退出while,run方法里的notifyAll就是用来唤醒这里的
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
2、Handler,message,looper
它们之间的关系如下:
(1)Looper:相当于消息的载体
• 它的内部有一个消息队列,也就是MessageQueue,Handler发送的所有消息都会走向这个消息队里。
• 它的Looper.loop方法是一个死循环,不断的从消息队列MessageQueue中取出消息。如果有消息存在就处理该消息,否则就阻塞。
(2)MessageQue:是一个消息队列,可以向其中添加消息并处理消息。
(3)Handler:是发送消息处理消息的封装。它与Looper相关联,也就是说在Handler的内部可以找到Looper,找到了Looper就找到了相应的消息队列。因此Handler发送的消息都会走向MessageQueue。
也就是说Handler负责发送消息和接收Looper传过来的消息,并根据消息处理相应逻辑,Looper负责接收Handler发送过来的消息,并将该消息回传给Handler。而MessageQueue只是相当于一个消息容器
Paste_Image.png
(1)Looper
Looper主要有prepare()和loop()两个方法
A、先看prepare()方法:
private static void prepare(boolean quitAllowed) {
//判断了sThreadLocal是否为null,
//说明了Looper.prepare()方法不能被调用两次,也保证了一个线程中只有一个Looper实例
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//将一个Looper的实例放入了ThreadLocal
}
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。
(当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响)
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
B、new Looper(quitAllowed):
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建了一个MessageQueue(消息队列)
mThread = Thread.currentThread();
}
C、再看loop()方法:
public static void loop() {
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;//拿到该looper实例中的mQueue(消息队列)
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {//无限循环
//取出一条消息,如果没有消息则阻塞
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//把消息交给msg的target的dispatchMessage方法去处理
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();//释放消息占据的资源
}
}
第二行,关于myLooper:
public static Looper myLooper() {
//返回了sThreadLocal存储的Looper实例,如果为null则抛出异常
//也就是说looper方法必须在prepare方法之后运行
return sThreadLocal.get();
}
可以看到Looper主要作用:
1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
(2)Handler:
A、Handler的构造方法:
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();//获取了当前线程保存的Looper实例
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取了这个Looper实例中保存的MessageQueue(消息队列)
//这样handler的实例与我们Looper实例中MessageQueue关联上了
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
B、发送消息sendMessage
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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) {
//Looper的loop方法会取出每个msg然后交给msg.target.dispatchMessage(msg)去处理消息
//也就是把当前的handler作为msg的target属性
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//保存到消息队列中
}
C、消息分发:
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) {
}
为什么是一个空方法呢?因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理
例如:
private Handler mHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case value:
break;
default:
break;
}
};
};
总结:
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法