Handle在Android中的定位
1.所有的事件都是通过handle message 分发的。
通过launcher (app) 管理其他应用APP的启动,利用zygote进程,fork一个新进程,分配jvm虚拟机(保证数据完整性,安全性)。每个java类,都是通过一个main()函数启动,我们的应用APP也是通过ActivityThread.main() 函数启动,并且在此函数中,构建了Looper实例对象,执行了Looper.loop() 函数,用来不断循环的取出消息。所以主线程中默认有Looper,创建new Handle,不需要自定义Looper对象。
ActivityThread main()
public static void main(String[] args) {
....
Looper.prepareMainLooper(); //构造Looper实例对象
.....
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); //返回 new handler()创建的实例对象
}
.....
Looper.loop(); //死循环,轮播消息,分发给handle.handleMessage
....
}
Handle工作流程
1.子线程中 Handle发送消息
2.MessageQueue把消息加入队列(MessageQueue只是一个容器,没有线程)
3.主线程 中的 Looper把消息从队列中 取出来,分发给handle
4.handle在回调函数中 处理数据(主线程)
5.如此一个循环步骤,实现了线程之间的通信
源码解析
1.handler 发送消息 ,最终会调到sendMessageAtTime--》enqueueMessage()
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) {
//msg消息 拥有handle,如果handle是内部类,那么有可能造成内存泄露
msg.target = this;
....
return queue.enqueueMessage(msg, uptimeMillis);
}
2.MessageQueue enqueueMessage() 把消息加入队列
MessageQueue 是个单链接优先级队列
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {//同步锁,保证数据队列的线程安全
....
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//判断消息的优先级,确定插入队列位置
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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) { //messageQueue为null时,进入睡眠状态
nativeWake(mPtr);
}
}
return true;
}
3.Looper .prepare() 构建Looper实例对象,加入ThreadLocal
Looper .prepare() 构造Looper()实例对象,Looper()是私有构造函数
整个APP 只有一个ThreadLocal 对象实例,利用ThreadLocalMap存储Looper实例,保证一个线程,只有一个Looper
static final ThreadLocal sThreadLocal = new ThreadLocal();
//sThreadLocal 存储Looper实例的实现函数
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//key是当前线程,value是Looper实例,所以一个线程只有一个Looper
createMap(t, value);
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //一个线程只有一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//构建 主线程的Looper,在ActivityThread.main()调用,
//所以主线程new handle,不需要对Looper进行实例化
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//以thread为key,在ThreadLocalMap中取出存储的Looper实例对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* 获取主线程的Looper对象实例
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
4. Looper.loop() 循环遍历messageQueue,取出Message
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
...
for (;;) { //利用死循环,循环取出messageQueue中的message,分发给handle的接口函数handleMessage()
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
...
try {
//调用handle dispatchMessage
msg.target.dispatchMessage(msg);
...
} catch (Exception exception) {
....
} finally {
.....
}
....
//对message进行清空处理,复用内存,避免内存碎片,产生内存抖动,造成oom
msg.recycleUnchecked();
return true;
}
//messageQueue 通过next() 取出消息
Message next() {
final long ptr = mPtr;//是否进入睡眠状态
if (ptr == 0) {
return null;
}
......
for (;;) {
.....
synchronized (this) {
....
Message prevMsg = null;
Message msg = mMessages;
......
if (msg != null) {
....
} else {
......
return msg;
}
}
.....
if (mQuitting) { //Looper 调用了quit() 清空全部message信息
dispose();
return null;
}
..........
}
}
//handle dispatchMessage,把message 回调给handleMessage()函数
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
6.Message 类的 obtain(),享元设计模式,复用内存
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//message对象,数据清空,复用内存
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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
面试题解析
1.一个线程有几个Handler?
可以有很多个Handler,在主线程中 new Handler(), 在子线程中 new Handle(Looper) 必须传入对应Looper对象。
2.一个线程有几个Looper?怎么保证
一个线程只能有一个Looer,通过ThreadLocal的ThreadLocalMap来保证,在Looper实例化的时候,会把Looper实例化对象存在ThreadLocalMap中,key是当前Thread。下次再调用Looper实例化函数prepare(),会先从ThreadLocalMap 读取以thread为key的数据,如果不为空,抛出异常。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //一个线程只有一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
3,Handler内存泄露的原因?为啥其他内部类没有这个问题?
内部类默认持有外部类对象,所以handler实例默认持有外部activity。
在handler发送消息的函数中,把handler对象赋值给了message,所以message持有了handler。而message的执行是不确定的,按照顺序执行的,如此一来即使activity退出页面,也不会被内存回收,造成内存泄露。可以使用静态内部 Handler来解决这个问题。
其他内部类 比如RecycleView adapter的viewHolder 为什么没有造成内存泄露,因为他跟着activity的生命周期,当activity退出,也会退出。
4.为何主线程可以直接new Handler(),子线程中想要new Handler()需要做哪些准备?
Handler中必须有一个Looper对象。
因为主线程在activityThread 的main()函数执行的时候,就已经创建了Looper的对象实例,并且调用了Loope.loop()函数,所以不需要在对Looper对象操作。
想要在子线程中 new Handler()实例对象,必须初始化mLooper = Looper.prepar()构建Looper实例对象,new Handler(mLooper) 创建handler对象,然后调用Looper.loop() 循环取出消息
5.子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
消息队列无消息的时候就进入睡眠状态,Looper.loop死循环,取出message 为null,就退出本次循环,然后再来一次。Looper.quit()调用MessageQueue的quit()
//Looper.quit()
public void quit() {
mQueue.quit(false);
}
//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(); //清除所有的message数据
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr); //进入睡眠状态
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked(); //清空数据,复用内存
p = n;
}
mMessages = null;
}
}
6.存在多个Handler 往messageQueue 中添加数据,内部是如何确保线程安全的?
利用锁来保证线程安全,synchronized 同步锁,也称之为内置锁,有jvm实现上锁和解锁操作。
messageQueue.enqueueMessage(),利用 synchronized (this) 对整个messageQueue对象上锁,对象里面的所有函数 代码块都会受到限制。并且一个线程中只有一个Looper,所有也只有一个可以操作messageQueue的地方,保证一个线程只有一个messagQueue对象。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
....
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;
}
7.使用Message时应该如何创建它?
为了保证内存的复用,Message使用了享元设计模式,通过提供的obtain()函数来构建Message对象,优先使用已分配内存并且清空数据的Message对象,如果不存在这样的内存对象,就new Message(只是个空函数) 构建message 对象,分配内存。
在message对象被分配给handle之后,会调用 msg.recycleUnchecked();清空数据,复用内存。
8.Looper死循环为什么不会导致应用卡死。
anr是应用无响应,当在主线程 执行点击操作 5s之内没有响应, 或者广播10s,服务20s,执行耗时操作没有结束任务,就会报出ANR 应用无响应 弹窗。
无论是点击事件,还是Anr事件都是一个message,都需要Looper循环取出的。
比如 一个点击事件,生成一个message,在5s之内没有处理该message,就会再发一个Anr message,因为他的优先级比较高,所以会先取出ANR的消息,展示弹窗。
所以Looper的死循环和Anr不是一个层级的问题。
9.Handler 是怎么实现多线程通信的?
子线程中,通过主线程创建的handler对象实例发送消息,调用messagQueue把消息加入消息队列。messagQueue只是个容器,没有线程的区别。
因为主线程创建的handler对象实例,所以handler 对应的looper就是ActivityThread main() 函数创建的looper。
主线程中Looper.loop() 调用messagQueue.next() ,获取对应的message消息,通过handler.dispatchMessage() ,给回调函数handleMessage() 赋值。
子线程发送数据,主线程取出数据,就这样完成了线程之间的通信。
Handler的扩展使用
HandlerThread
HandlerThread 是Thread的子类,就是一个线程,只是在内部帮助实现了Looper实例化。
方便使用,保证了线程安全。
public class HandlerThread extends Thread {
.....
@Override
public void run() {
...
Looper.prepare();
synchronized (this) {//保证线程安全
mLooper = Looper.myLooper();
notifyAll();//激活所有等待的线程,进入就绪状态
}
....
Looper.loop();
.....
}
public Looper getLooper() {
.....
synchronized (this) { //保证线程安全,避免取出空looper
while (isAlive() && mLooper == null) {
try {
wait(); //进入等待状态
} catch (InterruptedException e) {
.....
}
}
}
......
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) { //内部创建Handler实例对象
mHandler = new Handler(getLooper());
}
return mHandler;
}
......
}
IntentService
是Service的子类,一般用于处理后台耗时任务。内部封装 HandlerThread实现子线程处理耗时任务。
内部创建了Handler 实例对象,用来分发数据给回调函数 onHandleIntent((Intent)msg.obj);
一个任务分成几个子任务,子任务按照顺序先后执行,子任务全部执行结束后,这项任务才算成功。intentService就能完成这个任务,并且很好的管理线程,保证只有一个子线程处理工作,而且是一个一个完成任务,有条不紊的顺序执行
@Deprecated
public abstract class IntentService extends Service {
....
//子线程 handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//回调数据
stopSelf(msg.arg1);
}
}
....
@Override
public void onCreate() {
super.onCreate();
//构建线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
//构建子线程的handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
....
@Override
public void onDestroy() {
//退出循环
mServiceLooper.quit();
}
....
@WorkerThread //因为handler是子线程创建的,所以此函数也工作在子线程,可以执行耗时操作
protected abstract void onHandleIntent(@Nullable Intent intent);
}