文章目录
- Handler学习笔记
- 应用启动了解
- Handler 运行流程
- Handler机制的组成部分
- HandlerThread
- IntentService
- Handler机制常见问题
- 1. 一个线程可以有多少个Handler?
- 2. Handler内存泄露原因?为什么其他的内部类没有说过有这个问题?
- 3. 为什么主线程可以new Handler? 如果想要在子线程中new Handler 要做些什么准备?
- 4. 子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
- 5. MessageQueue 消息队列的阻塞问题?(分析流程与第4问一样)
- 6. 既然可以存在多个Handler往MessageQueue中添加数据(发送消息时各个Handler可能处于不同线程),那它如何确保线程安全的?
- 7.主线程中能执行Looper.quit()方法吗?
- 8.我们使用Message时应该如何创建它?
- 9.Looper的死循环中Block(阻塞)为什么不会导致应用卡死?
Handler学习笔记
概要:Handler就是我们常说的消息管理机制,它是实现线程间通信的方式,它的内部原理主要是利用内存共享来达到线程通信的。
应用启动了解
在学习Handler前,我们先了解一下Android应用的启动:
整个手机屏幕相当于一个lancher(app)桌面应用程序,点击屏幕中的其他应用图标就相当于与点击lancher中的某个控件,就会响应进行zygote操作,zygote就会给当前需要运行的应用fork一个进程同时分配一个jvm,然后这个jvm就会启动ActivityThread.java 中的main()函数。
zygote 为什么要给每个应用都分配一个jvm:目的是为了实现每个应用间的隔离,应用间相互独立互不影响,当一个应用崩溃了不会影响到其他应用的正常运行。
public final class ActivityThread {
......
public static void main(String[] args) {
......
Environment.initForCurrentUser();//初始化环境
.....
Looper.prepareMainLooper();//准备主线程的Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//开始消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");
}
......
}
从上面代码可以看出一个应用的主线程的Handler机制中的Looper循环维持着整个应用的运行,从Looper.loop()方法的源码中可以看出里面维持着一个死循环操作,不断的从MessageQueue中拿出message,再由handler来进行分发处理。
public final class Looper {
......
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;
// 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) {
//当msg为null时才会退出死循环
// No message indicates that the message queue is quitting.
return;
}
......
try {
//开始分发消息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.......
msg.recycleUnchecked();
}
}
......
}
Handler 运行流程
在上面的机械运动示例图中,好像message 在运动传递;实际在Handler 机制中 Message 就是一块内存,内存是不区分线程的,所以Handler 才能在线程间(主线程与子线程、子线程与子线程)之间通过Message传递事务。
Handler消息入队流程
Handler调用post/sendMessage()方法------》
最终都会进入Handler.sendMessageAtTime()------》
接着调用Handler.enqueMessage()------》
最后执行MessageQueue.enqueueMessage()将消息放入MessageQueue消息队列中。
public class Handler {
......
//post方法
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
//send方法
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);
}
//post/send 最终都会进入的方法
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);
}
}
public final class MessageQueue {
//消息入队列方法
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
}
Handler消息出队流程
Looper.loop()------》
在for循环中调用 MessageQueue.next()方法取出message------》
再由 Handler.dispatchMessage() 分发消息------》
最后执行Handler.handleMessage()处理消息。
public final class Looper {
......
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;
// 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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//在此分发消息,msg.target 就是 handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
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();
}
}
......
}
public class Handler {
......
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//在此调用方法处理消息
handleMessage(msg);
}
}
......
}
Handler机制的组成部分
Message
Message消息是事务的载体,它可以通过 new Message() 与 Message.obtain() 方法进行实例化。
MessageQueue
用于存放Message的消息队列:它是是一个由单链表实现的优先级队列。结构如下:
Message ------>Next------>Message ----->Next …
Next是Message 中的一个属性,类型也是Message
存Message
public final class MessageQueue {
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
//锁开始的地方
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
//消息队列没有头部,表示消息队列是空的
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
//循环队列,比较时间插入进消息队列中
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
//锁结束的地方
return true;
}
}
enqueueMessage()示例:
在上面实例中在执行MessageQueue.enqueueMessage()中的for循环时,会从M1开始循环比较M1与M4的执行时间M1.time<M4.time,继续比较M2.time < M4.time, 再继续比较 发现 M3.time >M4.time , 因此可以得出 M4要晚于M2执行早于M3执行,所以将M4插入M2、M3之间。
取Message
public final class MessageQueue {
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
......
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
//锁开始的地方
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//重点获取消息代码
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
//锁结束的地方
.............
}
}
Message.next() 示例:
在enqueueMessage()、next()方法中,存在:
synchronized (this)
synchronized锁是一个内置锁,也就是由系统控制锁的lock unlock时机的。这个锁,说明的是对所有调用同一个MessageQueue对象的线程来说,他们都是互斥的,然而,在我们的Handler里面,一个线程是对应着一个唯一的Looper对象,而Looper中又只有一个唯一的MessageQueue(这个在下文中会有介绍)。所以,我们主线程就只有一个MessageQueue对象,也就是说,所有的子线程向主线程发送消息的时候,主线程一次都只会处理一个消息,其他的都需要等待,那么这个时候消息队列就不会出现混乱。
Looper
核心知识点:Looper的构造函数、Loooer.loop()方法、ThreadLocal。
Looper的构造函数是一个私有的构造函数,因此在外部无法直接通过new来实例化Looper;因此Looper提供了相应的Looper实例化的方法。
私有化构造函数:在构造Looper的同时,也创建了一个MessageQueue的实例。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
主线程准备looper的方法:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
子线程准备looper的方法:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
在prepare()中发现是先从ThreadLocal中获取存储的looper 进行空判断,如果ThreadLocal中存在了looper再调用prepare()方法时会抛出异常,如果不存在则new一个looper放入ThreadLocal中。
通过比较发现主线程准备looper的方法中实则也是执行的prepare()方法。只是他们传入的参数不一样,主线程出入的是false ,通过梳理代码发现该参数会被传递进入MessageQueue中,在调用quit()方法时会用到。mQuitAllowed就是传入的参数。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
public final class Looper {
......
public void quit() {
mQueue.quit(false);
}
......
}
通过上面代码可以发现主线程是不能通过调用quit()方法来停止轮询的,否则会抛出 throw new IllegalStateException(“Main thread not allowed to quit.”)异常。
ThreadLocal
TreadLocal 多线程必须掌握的知识,是线程上下文的存储变量。
public class Thread implements Runnable {
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
}
每一个线程中都有一个ThreadLocal.ThreadLocalMap threadLocals = null;这个成员变量,用于存放跟线程相关的上下文环境数据的。
一个线程如何保证其只有一个Looper且是不可变的啦?
public class Thread implements Runnable {
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
}
public final class Looper {
......
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
......
}
public class ThreadLocal<T> {
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//将looper存入ThreadLocalMap中,这里的this其实就是Looper类中的sThreadLocal
map.set(this, value);
else
//如果线程的ThreadLocalMap 为空 则给该线程创建一个ThreadLocalMap 同时把looper 存入
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
/**
*ThreadLocalMap 它是ThreadLocal的一个静态内部类
***/
static class ThreadLocalMap {
//存数据方法
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//取数据方法
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
}
从上面代码可以看出当我们Looper.prepare()的时候,会调用ThreadLocal的set()方法,这时会判断Thread中的ThreadLocalMap是否已经创建,没创建会调用ThreadLocal.createMap()进行创建(每一个线程Thread,都有一个自己的ThreadLocalMap),创建成功后就会将Looper存入到Thread中的 ThreadLocalMap中,存的这行代码很关键:
map.set(this, value);
众所周知map.put(key1,value1),如果我们对相同的key1再次赋值map.put(key1,value2),则key1处的value1就会被value2覆盖。然而在这里this实际就是sThreadLocal
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
由于sThreadLocal是由static final 修饰的变量,它是全局不可变的,所以map.set(sThreadLocal ,value)中的key就是不可变的。既然key唯一了,那么可以继续对这个key设置value进行覆盖吗。答案是不可以的,因为在:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
在上面代码中首先就会通过sThreadLocal.get()从当前线程的ThreadLocalMap中通过唯一的key==sThreadLocal来拿一次Looper,如果获取到了Looper !=null,则会抛出throw new RuntimeException(“Only one Looper may be created per thread”)异常;如果发现ThreadLocalMap中没有存入Looper,这时才会new一个Looper存入当前线程中的ThreadLocalMap中。这样就保证了一个线程中只有一个Looper且是不可变的。
通俗点讲就是先限定ThreadLocalMap中的key唯一,然后如果这个key对应的value有值就抛出异常,没有就将Looper存入ThreadLocalMap。所以在线程中多次调用Looper.prepare()是会抛异常的。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在Looper的构造方法中,会创建一个MessageQueue,由于一个线程只有一个Looper所以Looper的构造方法在当前线程中只会被调用一次,所以MessageQueue也只有一个。如果一个线程中没有进行调用Looper.prepare()方法,则该线程中是不存在Looper和MessageQueue的。
同步屏障
屏障的意思即为阻碍,顾名思义,同步屏障就是阻碍同步消息,只让异步消息通过。
在Handler中,大致分为3种Message,分别是同步消息,异步消息和同步屏障。
public class Handler {
......
final boolean mAsynchronous;//异步开关
public Handler() {
//通常new Handler() 默认false 表示不将消息设置为异步消息
this(null, false);
}
public Handler(Callback callback) {
//通常new Handler() 默认false 表示不将消息设置为异步消息
this(callback, false);
}
public Handler(Looper looper) {
//通常new Handler() 默认false 表示不将消息设置为异步消息
this(looper, null, false);
}
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;
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
//设置Message为异步消息
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
......
}
同步消息:通过上面的代码可以看出,平时使用的消息是同步消息,因为Handler中传入的mAsynchronous为false。
异步消息:就是将mes.setAsynchronous(true)的消息称为异步消息,可以通过下面的方式设置异步消息:
HandlerHandler mHandler = new Handle(true)
同步屏障:虽然没有消息两字,但是同步屏障本质也是Message对象,同步屏障可以把它解释为:屏障同步消息的消息,它和前面同步、异步消息的最大区别就是,Message.target变量为null,它的作用就是在消息队列(MessageQueue)取出消息的时候,屏蔽掉同步消息,优先获取异步消息进行处理的作用。
- 如何开启同步屏障?
在MessageQueue中有对应的开启同步屏障的方法:
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
//从消息池中获取Message
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
//就是这里!!!初始化Message对象的时候,并没有给target赋值,因此 target==null
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
//如果开启同步屏障的时间(假设记为T)T不为0,且当前的同步消息里有时间小于T,则prev也不为null
prev = p;
p = p.next;
}
}
//根据prev是不是为null,将 msg 按照时间顺序插入到 消息队列(链表)的合适位置
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
可以看到,Message 对象初始化的时候并没有给 target 赋值,因此, target == null 的 来源就找到了。上面消息的插入也做了相应的注释。这样,一条 target == null 的消息就进入了消息队列。
- 那么,开启同步屏障后,所谓的异步消息又是如何被处理的呢?
public final class MessageQueue {
......
Message next() {
......
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
......
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;; //当前链表的头结点
//target == null 表示开启了同步屏障 然后开始循环消息队列中的消息
//如果消息是同步消息这继续循环,直到获取消息为异步消息,取出异步消息,跳出循环,然后处理异步消息。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.这句注释很重要
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
......
}
}
......
}
从上面可以看出,当消息队列开启同步屏障的时候(即标识为 msg.target == null ),消息机制在处理消息的时候,优先处理异步消息。这样,同步屏障就起到了一种过滤和优先级的作用。
- 移除同步屏障
在MessageQueue中也有对应的方法:
//@param token The synchronization barrier token that was returned by{@link #postSyncBarrier}.
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
传入的token调用postSyncBarrier()方法的返回值,也称为同步屏障令牌。
- 同步消息的应用场景
似乎在日常的应用开发中,很少会用到同步屏障。那么,同步屏障在系统源码中有哪些使用场景呢?Android 系统中的 UI 更新相关的消息即为异步消息,需要优先处理。比如,在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用了
ViewRootImpl#scheduleTraversals() ,如下:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//开启同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//发送异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
postCallback() 最终走到了 Choreographer.postCallbackDelayedInternal() :
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
//设置异步消息
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
这里就开启了同步屏障,并发送异步消息,由于 UI 更新相关的消息是优先级最高的,这样系统就会优先处理这些异步消息。
最后,当要移除同步屏障的时候需要调用 ViewRootImpl#unscheduleTraversals()方法:
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
同步屏障总结:同步屏障的设置可以方便地处理那些优先级较高的异步消息。当我们调用Handler.getLooper().getQueue().postSyncBarrier() 并设置消息的setAsynchronous(true) 时,target 即为 null ,也就开启了同步屏障。当在消息轮询器 Looper 在 loop() 中循环处理消息时,如若开启了同步屏障,会优先处理其中的异步消息,而阻碍同步消息。
HandlerThread
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
很方便的类,用于启动具有循环程序的新线程。 然后可以使用循环程序创建处理程序。 请注意,仍必须调用start()。
public class HandlerThread extends Thread {
......
@Override
public void run() {
mTid = Process.myTid();
//准备Looper
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//开启loop循环
Looper.loop();
mTid = -1;
}
......
}
从上面代码可以看出HandlerTread在期内部run()方法中已经创建了looper并开启了循环程序。
HandlerThread存在的意义:
1.方便使用:a.方便初始化,b.方便获取子线程的Looper;
2.为了保证线程的安全。
我们先来看看常规Thread的可能出现的问题:
class MyThread extends Thread{
public Looper getLooper() {
return looper;
}
Looper looper;
@Override
public void run() {
super.run();
Looper.prepare();
looper = Looper.myLooper();
//在子线程内部创建了一个子线程的handler
Handler handler = new Handler(looper);
Looper.loop();
}
}
private void test(){
MyThread myThread = new MyThread();
//开启线程
myThread.start();
//获取子线程的looper
Looper looper = myThread.getLooper();
//创建子线程的handler
Handler threadHandler = new Handler(looper);
}
执行上面的test()方法,当new Handler(looper)时可能会因为looper为空而抛出异常。为什么会出现这种情况啦,是因为子线程myThread.start()的时候 myThreadd的run()方法是异步的,然而new Handler(looper)则是同步的,这就有可能导致myThread线程中的looper还未创建所以传入Handler的looper为空。
那么HandlerThread是如何避免这个问题的啦?
public class HandlerThread extends Thread {
......
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
//获取looper
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;
}
......
}
在上面代码中如果先调用getLooper()当进入synchronized内的代码,发现mLooper为null首先会执行wait()等待, wait()方法会释放synchronized所持有的锁,此时run()方法执行了,然后run()方法中的synchronized锁住其内部代码,执行到notifiAll()会唤醒等待,但是notifiAll()不会释放锁这时getlooper()的循环还是不能立刻执行,需要等到run()方法中的synchronized代码块执行完了以后才能执行,因此就保证了looper是一定能获取的。
IntentService
IntentService:也是一种service,一般用于后台处理耗时任务。
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//内部类ServiceHandler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//5.就会调用接收message, 在onHandleIntent()中处理自己的逻辑(如耗时操作等)
onHandleIntent((Intent)msg.obj);
//6.自动停止service
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//1.创建一个子线程 由于使用的是HandlerThread 所以内部自动生成了looper,并且调用了Looper.loop()
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//2.获取子线程的looper
mServiceLooper = thread.getLooper();
//3.创建一个属于子线程的 handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//4.当调用 service的onStart()生命周期方法时,就会自动通过子线程的handler向子线程发送一个message
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
Service的生命周期是由后台调度的,在IntentService的onCreate()方法中创建了一个异步线程HandlerTread同时开启它,并在onStart()方法中向异步线程发送一个Message消息,然后通过异步线程的handleMessage()方法调用onHandleIntent()方法处理耗时操作。onHandleIntent是一个抽象方法,在new IntentService时需要实现该方法。IntentService还有一个好处是:在handleMessage中处理完onHandleIntent()中的耗时任务后,会执行stopSelf()方法来自动停止Service,从而达到内存的自动释放。
IntentService的应用场景:
有一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。
方式一:可以用多个线程来执行 一个线程执行完—>下一个线程---->下一个线程—>…
方式二:就采用IntentService来完成,IntentService能够很好的管理线程,保证只有一个子线程处理工作,而且是一个一个的完成任务,按顺序执行的,因为其内部是由一个HandlerThread的MessageQueue来保证任务顺序的执行。
public void onClick(View view) {
//请求1
Intent intent1 = new Intent("cn.service");
intent1.setPackage(getPackageName());
Bundle bundle1 = new Bundle();
bundle1.putString("Flag","one");
intent1.putExtras(bundle1);
startService(intent1);
//请求2
Intent intent2 = new Intent("cn.service");
intent2.setPackage(getPackageName());
Bundle bundle2 = new Bundle();
bundle2.putString("Flag","two");
intent2.putExtras(bundle2);
startService(intent2);
}
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
super("myIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Bundle extras = intent.getExtras();
String flag = extras.getString("Flag");
switch (flag){
case "one":
Log.e(TAG,"do task1");
break;
case "two":
Log.e(TAG,"do task2");
break;
}
}
}
Handler机制常见问题
1. 一个线程可以有多少个Handler?
答:理论上可以有无数个,因为可以无限的new Handle,实际要受内存的限制。
2. Handler内存泄露原因?为什么其他的内部类没有说过有这个问题?
答:从生命周期来考虑这个问题。
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
onclick(view); // ①
MainActivity.this.onclick(view);②
}
};
private void onclick(View view) {
}
上述代码中①、②处的代码是等价的,说明 handler(非静态内部类)内部自动持有了外部的MainActivity类,从生命周期来说,如果handler不销毁这MainActivity就没法被销毁。
Handler 代码中:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
........
rn 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);
}
Msg.target = this; this就是handler,说明Message中持有了Handler的引用,如果给Message加上了延迟时间,就会导致Message持有的handler引用的生命周期变长,进而导致handeler持有的Activity的引用的生命周期变长,如果此时Activity finish掉了,由于handler中还有未处理的message,同时handler又持有了Activity实例的引用,这样GC垃圾回收机制就不会去回收这个Activity,进而导致activity泄露。
可以将Handler定义为静态内部类,因为静态内部类不会持有外部类的应用;如果需要使用外部类的成员,可以用WeakReference 包裹外部类的对象将外部类对象传入Handler。
至于其他内部类为什么没有没有内存泄露的问题:是因为其他内部类的生命周期维持着和外部类的生命周期一样。比如RecyclerView ---->Adapter—>ViewHolder。
3. 为什么主线程可以new Handler? 如果想要在子线程中new Handler 要做些什么准备?
答:
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()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们从Handler的构造方法中可以看出,在new Handler 之前需要有一个looper,否则会抛出异常。
在ActivityThread#main()方法中可以知道
ublic static void main(String[] args) {
......
Looper.prepareMainLooper();
.......
Looper.loop();
.......
}
此时在主线程中已经创建了Looper,所以在主线程中可以直接进行new Handler() 的操作。因此在子线程中我们想要new Handler()就必要先要调用Looper.prepare()方法为子线程创建一个唯一的Looper,同时还要进行Looper.loop()操作。
注意:通过代码实践发现部分华为手机在子线程中不调用Looper.prepare()也能直接进行new Handler()操作,猜测华为系统对Android源码进行了改动,当子线程没有looper时,系统内部会创建一个looper。
4. 子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
答:当消息队列中无消息的时候,应该让Looper退出loop()方法,那么如何让Looper退出loope()方法,进行下面的分析:<font color = "#ff000">nativePollOnce()、nativeWake()为底层方法。</font>
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
首先我们看看如果队列中无消息的时候会造成怎样的后果:
a.Message msg = mMessages;mMessages为空,所以拿到的msg也为空;
b.代码就会走到nextPollTimeoutMillis = -1;
c.就会执行到continue,继续下一次循环;
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
d.回到for循环体顶部,当执行到 nativePollOnce(ptr, nextPollTimeoutMillis);第2步中nextPollTimeoutMillis=-1,会导致一直阻塞在nativePollOnce里;
e.所以当子线程的消息队列中无消息时会在Looper.loop()方法中的Message msg = queue.next(); 处阻塞着。
为了退出这个阻塞,并让next()方法返回null啦,源码中有这样一段代码
if (mQuitting) {
dispose();
return null;
}
程序在什么地方会赋值mQuitting=true啦,继续追踪发现:MessageQueue#quit()
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
在上面的代码中 mQuitting = true,同时同时调用removeAllMessagesLocked()清理消息,并且nativeWake(mPtr)方法会使nativePollOnce(ptr, nextPollTimeoutMillis);跳出阻塞继续往下走,再次走到
if (mQuitting) {
dispose();
return null;
}
此时mQuitting=ture,则next就会返回null,从而跳出Looper.loop()循环。
继续寻找调用MessageQueue#quit()方法的地方,发现:Looper#quit()
public void quit() {
mQueue.quit(false);
}
因此当子线程消息队列中无消息的时候,应该让Looper退出loop()方法,退出的措施是调用Looper.quit();
上面的分析流程也适用于延时Message的阻塞问题。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
当nativePollOnce(ptr, nextPollTimeoutMillis)阻塞时间到达后就会继续往下执行。
5. MessageQueue 消息队列的阻塞问题?(分析流程与第4问一样)
答:一般的生产者-消费者模式中,经常会遇到入队列和出队列的阻塞问题,但是MessageQueue是有点特殊的生产者-消费者模式。即在MessageQueue.enqueue()时不对加入消息数量做限制,理论上可以无限加,实际受限于存储空间。为什么不设置加入限制啦?是因为系统的消息也是通过这个方法加入的。然后看看MessageQueue.next()会出现的阻塞:
①要取的第一个消息还没到执行时间 (到时间自动唤醒);
②消息队列中已经没有消息,无限等待
//传入的timeoutMillis 如果为-1 表示无限等待,直到有事件发生为止;如果为0表示无需等待
private native void nativePollOnce(long ptr, int timeoutMillis);
Message next() {
......
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);//睡眠
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
......
if (msg != null) {
//消息队列有消息
if (now < msg.when) {
//还未到执行时间
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//获取等待时间
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
//消息队列没有消息了,则为-1 表示一直等待
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
......
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
......
}
}
1)当消息未到执行时间的情况,会获取等待时间然后调用nativePollOnce(ptr, nextPollTimeoutMillis)进行等待,时间到达后自动唤醒;
2)2.当消息队列中没有消息时,nextPollTimeoutMillis = -1; 此时在调用
nativePollOnce(ptr, nextPollTimeoutMillis);则会一直等待,直到有事件发生为止,如果某一刻有新的消息加入则会调用enqueueMessage()方法中的nativeWake()方法唤醒。
6. 既然可以存在多个Handler往MessageQueue中添加数据(发送消息时各个Handler可能处于不同线程),那它如何确保线程安全的?
答:Snchronized:内置锁(上锁、解锁)都是由JVM完成。在MessageQueue中enqueueMessage()、next()、quit()中都有synchronized(this){}锁住当前类,因此在执行enqueueMessage()、next()、quit()时MessageQueue中的其他函数都处于等待状态。并且一个线程只有一个MessageQueue,在配合着MessageQueue 中的调用方法中添加了锁,因此能够保证线程的安全。
类锁
MessageQueue mq1 = new MessageQueue;
mq1.enqueueMessage();
MessageQueue mq2 = new MessageQueue;
mq2.enqueueMessage();
Synchronized(MessageQueue.this){}
如果正在调用mq1.enqueueMessage();则mq2.enqueueMessage();只能等待着mq1执行完后释放了锁后,才能执行。
对象锁:
MessageQueue mq1 = new MessageQueue;
mq1.enqueueMessage();
mq1.next();
MessageQueue mq2 = new MessageQueue;
mq2.enqueueMessage();
Synchronized(mq1){}
mq1.enqueueMessage()、mq2.enqueueMessage()的执行护不影响,但是mq1.next();只能等待着mq1执行完后释放了锁后,才能执行。
7.主线程中能执行Looper.quit()方法吗?
答:不能在主线程中执行quit()方法,会抛出异常:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
......
}
8.我们使用Message时应该如何创建它?
答:通过new Message()或者Message.obtain().(享元设计模式)内存复用。
为什么要obtain啦?因为在Looper.loop()中有回收的代码:
public static void loop() {
......
msg.recycleUnchecked();
}
Message#recycleUnchecked()
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
在Looper#loop()中会将处理了的message的内部数据全部置空,然后在sPool前加入该Message,这样回收的Message就维持了一个池子。那么为什么要这样处理啦?目的就是为了避免内存抖动,防止OOM. 原因是在一块完整的内存中通过new就会不断地去扣一块对应的内存,虽然使用后会释放但是会出现内存碎片,Android事务的处理都是基于message的传递 如果大量的消息全部都通过new, 则频繁创建的对象和频繁的GC回收对象会导致内存抖动(已用内存忽高忽低),而且GC回收后可能会产生内存碎片,如果这时其他线程需要申请大块内存但是又找不到就可能发生OOM。
9.Looper的死循环中Block(阻塞)为什么不会导致应用卡死?
答:Looper死循环和应用ANR毫不相关的两个问题。Looper循环是从MessageQueue中拿Message给程序处理;ANR是程序处理不能在有效时间内给出响应。它们是两个独立的过程Looper循环拿消息,至于拿不拿得到、要等多久能拿到,与程序处理而未响应(ANR)一点关系都没有。
例如:点击事件5s没处理:其实点击事件最终也会转换为Message, 如果处理这个Message的时间超过5s,就会使用handler发送一个超时的ANR的Message提醒。
以上是对Handler的学习和简单理解,如有错误之处还请谅解。