https://juejin.im/post/5ba657e0f265da0a8b5722c2
一、Handler机制之ThreadLocal
ThreadLocal 是线程内部的数据存储类,通过它可以在指定线程中存储数据。
数据存储后,只有在指定线程中可以获取到存储的数据。
不同线程访问同一个ThreadLocal 对象,获取到的值是不一样的。
原因:
不同线程访问同一个ThreadLocal的get()方法,
ThreadLocal 内部会从各自线程中取出一个数组 ThreadLocalMap.table,
然后从数组中根据当前ThreadLocal 的索引,去查找出对应的value值。
不同线程中的数组是不同的,所以获取到的值也是不一样的。
每个线程中都有 ThreadLocalMap threadLocals,内部是一个哈希表(数组)
ThreadLocal对象的哈希值作为哈希表索引 ,数组对应索引的位置存储了值
Thread模型
public class ThreadLocal<T> {
/**
* get()查询的源数据,来自于调用线程,是与线程绑定的。
*/
public T get() {
Thread t = Thread.currentThread();//获取调用线程
//获取调用线程的 ThreadLocalMap = t.threadLocals
ThreadLocalMap map = getMap(t);
if (map != null) {
//从 ThreadLocalMap 中 获取 key 为 ThreadLocal 对象的value值。
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
//先获取调用线程
Thread t = Thread.currentThread();
//获取调用线程的 ThreadLocalMap = t.threadLocals
ThreadLocalMap map = getMap(t);
if (map != null)
//key为 当前ThreadLocal 对象, 把value塞入 ThreadLocalMap 中。
map.set(this, value);
else
createMap(t, value);
}
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
/**
* ThreadLocal set() 方法保存的数据,存储在这个 Entry 数组中
* 元素的下标为,当前ThreadLocal 对象的 哈希值算出的值。
* 数组元素为set(value) 传入的值。
*/
private Entry[] table;
private void set(ThreadLocal<?> key, Object value) {
//真正存储数据的是这个数组
Entry[] tab = table;
int len = tab.length;
//根据 threadLocal对象(key)的哈希值算出数组下标
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) {//把保存的value,传入到Entry对象的value字段
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();
}
/**
* 根据 threadLocal 对象的哈希值,算出数组下标,取出数组元素 Entry对象
* value 就存在 Entry 对象的 value字段中
*/
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);
}
}
二、Handler机制之Looper、Handler、MessageQueue
1、 Handler 的作用是
将自己的引用赋值给 Message#target,然后将 Message 对象发送到 MessageQueue 中去
子线程中使用:
-
Handler 与 Looper的 关联
Looper looper = Looper.myLooper(); Handler handler = new Handler(looper);
-
Handler 工作原理
public class Handler { //构造函数传入的 mCallback final Callback mCallback; public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } /** * 发送消息,会把Runnable 塞到 Message.callback 中 * 再把 Message 塞到队列 * 所以 handler.post() 方法, * 是把 Runnable 塞到handler 所在线程消息队列尾部。 */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } //处理消息 public void dispatchMessage(Message msg) { /** * msg.callback 就是 post(Runnable) 发送的 Runnable */ if (msg.callback != null) {//优先执行 post()传过来的消息 handleCallback(msg); } else { if (mCallback != null) {//其次执行构造函数传入的 mCallback.handleMessage if (mCallback.handleMessage(msg)) { return; } } //最后才是执行 handler的 handleMessage()方法 handleMessage(msg); } } }
handler.post(Runnable)
把Runnable 赋值给 Message.callback,然后把 Message 塞到队列尾部
所以 handler.post() 方法,是把 Runnable 塞到handler 所在线程消息队列尾部
2、 Looper
-
1)子线程中 Looper 的使用
Loopr.prepare(); Handler handler = new Handler(); Looper.loop();
-
2)Looper 与 Thread 的关联
Looper 与 Thread 通过 ThreadLocal 关联
Looper.prepare()方法中,创建一个Looper对象,通过ThreadLocal,存到当前线程的 threadLocals 哈希表中 -
3)Looper#loop()的作用
死循环,将 Message 对象从 MessageQueue 中取出来,交给 Handler#dispatchMessage(Message) 方法
不是 Handler#handleMessage(Message) 方法public final class Looper { final Thread mThread; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //创建一个Looper对象,存到当前线程的 ThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); } 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; ... //无限循环,从消息队列中取消息 for (;;) { //调用的 MessageQueue 的 next() 方法 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... try { //msg.target 就是把msg塞入消息队列的那个 Handler 对象 msg.target.dispatchMessage(msg); dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } finally { ... } ... } } }
3、 MessageQueue 的作用负责插入和取出 Message
MessageQueue是有序的单链表。排序规则是,根据 Message#when 字段。
插入:MessageQueue#enqueueMessage()
取出:MessageQueue#next()
队列消息为空时,会阻塞线程。有消息时,唤醒线程。
public final class MessageQueue {
/**
* 消息队列的插入操作:单链表插入,以when为排序依据
*/
boolean enqueueMessage(Message msg, long when) {
...
Message prev;
for (;;) {
prev = p;
p = p.next;
//按when 的值排序,小的排前面,大的排后面
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
...
if (needWake) {
nativeWake(mPtr);//有新消息时,唤醒线程
}
}
/**
* 读取消息,一个死循环,没有消息时,没有return 任何东西,一直保持循环阻塞阻塞线程
*/
Message next() {
...
for (;;) {
...
//阻塞线程 nextPollTimeoutMillis 毫秒,-1表示永久阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
if (msg != null) {
...
msg.markInUse();
return msg;
} else {
/** 没有消息时,设置一下阻塞时间 nextPollTimeoutMillis
* 阻塞时间 -1 表示永久阻塞,在下一次循环时会阻塞
*/
// No more messages.
nextPollTimeoutMillis = -1;
}
...
}
...
}
}
}
Message#when 字段,是由 MessageQueue#enqueue(Message, Long) 方法设置的。
是系统启动开始、到调用方法时的 mills + 入参 delayMills 之和,是个相对系统启动时间点的值。
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
SystemClock#uptimeMillis():自系统启动开始到调用该方法时相差的毫秒数
这里不用System.currentTimeMills(),修改系统时间会影响这个值,所以不可靠
因为它表示从1970-01-01 00:00:00 到当前时间的毫秒值。
4、 Handler、Looper、ThreadLocal、线程、MessageQueue 关系
各个对象的从属关系:
Thread {
//每个线程类都有的数组:thread.threadLocals,内部包含一个Entry[]
ThreadLocalMap {
//Entry数组的下标是ThreadLocal的哈希值算出
/* Entry数组中存了个 Looper 对象,
* Looper在数组中下标是,Looper类中的静态变量sThreadLocal 的哈希值算出的
*/
ThreadLocal : Looper {
//Looper中由一个单链表消息队列
MessageQueue {
//消息队列中装了由handler塞入的消息Message
Message {
//Message的target字段持有消息发送者handler的引用
target ->Handler
}
}
}
}
}
Handler {
//handler中持有当前线程的looper对象引用
currentThread.Looper
}
Looper == Thread # threadLocals # table [ ThreadLocal # threadLocalHashCode ]
线程的 threadLocals 哈希表中,存了一个 Looper 对象,Looper.prepare()方法中存进去的
Looper { MessageQueue [ Message#target == Handler ] }
Looper 中包含一个 MessageQueue 单链表有序队列,用于存取 Message
Message#target 用于保存发送消息的 Handler 的引用
Handler # Looper
Handler 中,持有当前线程的哈希表中 Looper的引用
所以,在任何非创建Handler 的线程,
只要持有 Handler 的引用,就可以给Handler所属线程的Looper的消息队列中塞入消息。
轮询取出消息后,通过 msg.target.dispatchMessage(msg),把消息交由handler处理。
比如:
1)在线程 A 创建了 Handler 对象,Handler 中持有线程 A 的 Looper 对象。
线程 A 在一直不停的轮询 looperA.messageQueueA。
线程A [ handlerA , looperA ]
2)线程 B 中,拿到 handlerA 的引用。
线程 B 中,执行完耗时操作,比如网络请求后,创建一个 MessageB
线程 B 中,handlerA.sendMessage(MessageB),把消息塞到了专属于线程A 的looperA的消息队列中。
3)线程 A 轮询 looperA.messageQueueA,取出了 MessageB
MessageB.target.dispatchMessage(MessageB)
线程 A 的 dispatchMessage 方法中,根据 MessageB 传递的消息,执行操作,比如更新UI。
三、Handler机制之Message的发送、取出
1、 发送消息的方法:
sendMessage(Message msg)
sendMessageDelayed(Message msg, long updateMills)
post(Runnable r)
postDelayed(Runnable r, long updateMills)
sendMessageAtTime(Message msg, long when)
sendEmptyMessage(int what)
sendEmptyMessageDelayed(int what, long updateMills)
sendEmptyMessageAtTime(int what, long updateMills)
2、 取出消息
Looper.loop()
-> MessageQueue.next()
-> Message.target.dispatchMessage()
-> handler.handleMessage()
四、Handler 中 Message 的回收机制
1、从消息池中获取消息
Message中 单链表对象池:MAX_POOL_SIZE = 50
static Message sPool 全局共用
public final class Message implements Parcelable {
public static final Object sPoolSync = new Object();
//Message 单链表对象池,静态的,为了全局共用
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; //重新标识当前Message没有使用过
sPoolSize--;
return m;// 从对象池中取出头部的 Message
}
}
return new Message();
}
}
2、回收消息到消息池
Message # recycleUnchecked()
public final class Message implements Parcelable {
public static final Object sPoolSync = new Object();
//Message 单链表对象池,静态的,为了全局共用
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
public void recycle() {
if (isInUse()) {
...
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
//用于表示当前 Message消息,已经被使用过了
flags = FLAG_IN_USE;
//清空之前 Message 数据
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
//判断当前消息池中的数量是不是小于最大数量,其中 MAX_POOL_SIZE=50
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;//记录当前消息池中的数量
}
}
}
}
五、Handler机制之 循环消息队列的退出
Loop.loop() 不会自动退出。
MessageQueue 空了以后,会阻塞等待。
可以通过 Looper#quit() 或者 Looper#quitSafely() 退出
六、Handler机制之内存泄漏
Message#target == handler
引用链: Activity <- Handler <- Message
handler.postDelay()
退出页面时,没有把handler里对应消息清空,会导致 Activity引用被持有无法释放,导致内存泄露。
Handler 在使用时,如果直接采用内部类,有可能会导致内存泄漏。
Handler内存泄漏原因:内部类 Handler拥有外部类 Activity的引用,且不能保证消息的发送是否有较长延时。
解决Handler内存泄漏的主要方法有:
采用静态内部类+弱引用
当外部类生命周期结束时,清空消息
七、Android中提供的对象池
1、同步对象池
android.support.v4.util.Pools$SynchronizedPool
2、简单对象池
android.support.v4.util.Pools$SimplePool
3、使用
public class MyPooledClass {
//声明对象池的大小
private static final SynchronizedPool<MyPooledClass> sPool =
new SynchronizedPool<MyPooledClass>(10);
//从对象池中获取数据,如果为null,则创建
public static MyPooledClass obtain() {
MyPooledClass instance = sPool.acquire();
return (instance != null) ? instance : new MyPooledClass();
}
//回收对象到对象池中。当然你也可以清除对象的状态
public void recycle() {
// 清除对象的状态,如果你自己需要的话,
sPool.release(this);
}
}
八、Handler机制之IdleHandle的理解及使用
looper 中 message 暂时处理完了,这个时候会回调 IdleHandler # queueIdle() 接口
返回false,执行后会移除该 IdleHandler
返回true,下次 message 处理完的时候,继续回调
public final class MessageQueue {
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
public static interface IdleHandler {
/**
* 在looper里面的message暂时处理完了,这个时候会回调这个接口,
* 如果回调实现方法中返回false,那么就会移除它,
* 回调方法中返回true,就会在下次message处理完了的时候继续回调
*/
boolean queueIdle();
}
Message next() {
... //处理 messageQueue 中消息
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(TAG, "IdleHandler threw exception", t);
}
// 返回false,从 mIdleHandlers 中移除
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
}
IdleHandler 使用:
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
//在Looper.messageQueue 中消息执行完之后,回调该方法
return false;//返回false,执行完上面代码后,从 mIdleHandlers 中移除
}
});
我们的 onResume和measure, layout, draw都是一个个 message 的话,
这个IdleHandler就提供了一个它们都 执行完毕的回调了。
1、在UI绘制完成后执行操作
我们在主线程的 Looper.messageQueue 中添加一个 IdleHandler,
那么在主线程的消息都执行完之后,会执行 IdleHandler 代码。
从而实现,在UI绘制完成时执行一些工作。
2、结合 HandlerThread 使用
//单线程操作完毕后通知外部
public AbsFavoriteModel() {
if (sThread == null) {
sThread = new HandlerThread("favorite-model");
sThread.start();
}
mHandler = new Handler(sThread.getLooper());
try {
Field field = Looper.class.getDeclaredField("mQueue");
field.setAccessible(true);
MessageQueue queue = (MessageQueue) field.get(sThread.getLooper());
queue.addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
if (mListeners != null){
for (DataChangeListener<T> mListener : mListeners) {
mListener.onDataChange(new ArrayList<>(mData));
}
}
return true;//返回true,用完后下次还要用,不移除
} });
} catch (Exception e) {
e.printStackTrace();
}
}
推荐阅读:
《Android开发艺术探索》第十章 10.2节 Android的消息机制
IdleHandle的奇思妙想----->你知道android的MessageQueue.IdleHandler吗?https://mp.weixin.qq.com/s/KpeBqIEYeOzt_frANoGuSg
Handler面试常问题目----->你真的懂Handler吗?Handler问答 https://www.jianshu.com/p/f70ee1765a61
如果大家不嫌弃,可以看看我的Handler机制总结----->Anroid Handler机制总目录 https://juejin.im/post/5ba65f57e51d4539701e47d6