1.Handler整体概括
在Android开发中会经常在子线程中进行一些操作,当操作完成后会通过Handler发送一些数据到主线程,通知主线程做相应的操作,Handler原理:子线程 Handler 主线程 其实构成了线程模型中的经典问题 生产者-消费者 模型。 生产者-消费者模型:生产者和消费者在同一时间段内用同一个存储空间,生产者往存储空间添加数据,消费者从存储空间中取走数据。
优点:保证数据生产消费的顺序(通过MessageQueue先进先出)-不管是生产者(子线程)还是消费者(主线程)都只依赖缓冲区(Handler),生产者和消费者之间不会相互持有,使他们之间没有任何耦合。
1.1Handler机制相关类
Handler:发消息和收消息
Looper:用于轮寻消息队列,一个线程只能有一个Looper
Message : 消息实体
MessageQueue : 消息队列用于存储信息和管理消息
ThreadLocal : 为每个线程提供单独的存储空间
ThreadLocalMap: ThreadLocal的内部类,set方法控制 对于每一个ThreadLocal只有一个value(looper)
Thread: 线程中持有一个threadLocals变量(ThreadLocal.ThreadLocalMap)
类图
1.2创建Looper
子线程:子线程中如果需要自己创建Looper调用Looper.prepare()方法,然后调用Looper.loop()方法。
主线程: 主线程ActivityThread中的main方法已经为我们创建了Looper
public static void main(String[] args) {
//省略其它代码.......
Looper.prepareMainLooper(); //初始化Looper以及MessageQueue
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); //开始轮寻
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.prepareMainLooper()
public static void prepareMainLooper() {
prepare(false); // 消息队列不允许quit,并创建Main Looper
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepare(boolean quitAllowed)
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//不为null表示当前线程已经创建了Looper
throw new RuntimeException("Only one Looper may be created per thread");
//每个线程只能创建一个Looper
}
sThreadLocal.set(new Looper(quitAllowed)); //将looper存储到ThreadLocal中,这样get的时候就不会为null,并且MessageQueue不允许quit
}
1.3创建MessageQueue以及Looper与当前线程绑定
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //创建MessageQueue
mThread = Thread.currentThread(); //当前线程绑定
}
MessageQueue的构造方法
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed; //mQuitAllowed决定了队列是否可以销毁,主线程的队列不可以被销毁需要传入false,在MessageQueue的quit方法中判断的
mPtr = nativeInit();
}
Looper.loop() 轮寻
public static void loop() {
final Looper me = myLooper(); //通过sThreadLocal.get()方法获取ThreadLocal中保存的Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //把Looper对象中的消息队列取出
// 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
//刚创建的MessageQueue中是没有消息的,等到Handler sendMessage enqueueMessage后队列里才有消息。
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
//return之后会执行ActivityThread中main的 throw new RuntimeException(“Main thread loop unexpectedly exited”)
//接着整个主线程就会退出了。所以就是说,在主线程中当loop()方法没有轮询到消息的时候。主线程就直接退出了
//所以在这里我们知道了Looper.loop()消息循环,一旦退出消息循环,那么应用也就退出了。
// 什么时候在进入呢??????
}
// 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);// msg.target就是绑定的Handler,调用Handler的dispatchMessage去处理消息
//后面代码省略......
}
}
创建Handler
最常见的handler创建方式
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
创建方式2:在内部调用this(null, false)
public Handler(Callback callback, boolean async) {
//前面代码省略......
mLooper = Looper.myLooper(); //获取ThreadLocal中的looper对象,子线程中使用Handler需要调用Looper.prapare,或者使用getMainLooper来使用主线程looper
//否则会抛出RunTimeException
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;
}
创建Message
可以直接new Message,但是更好的方式是Message.obtain. 因为可以检查是否有可以复用的Message,避免过多的创建、销毁Message对象达到优化内存和性能的目的。
public static Message obtain(Handler h) {
Message m = obtain(); //Message重载的obtain方法
m.target = h; //Message的handler和我们的handler绑定
return m;
}
obtain()
public static Message obtain() {
synchronized (sPoolSync) { //同步锁,保证线程安全
if (sPool != null) {
Message m = sPool; //sPool就是Handler dispatchMessage后通过recycleUncheckd回收以复用的Message
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Message和Handler的绑定
创建Message的时候可以通过Message.obtain(Handler h)这个构造方法进行绑定。当然在Handler中的enqueueMessage也进行了绑定,所有发送Message的方法都会调用此方法入队,所以在创建Message的时候可以不绑定
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //Message和Handler 进行绑定
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler发送消息
Handler发送消息的重载方法有很多,常用的主要有两个。1.sendMessage(Message), 它通过一系列重载方法的调用,sendMessage调用sendMessageDelayed,继续调用sendMessageAtTime,继续调用enqueueMessage,继续调用messageQueue的enqueueMessage方法,将Msg保存到消息队列中,最终由Looper取出,交给Handler的dispatchMessage进行处理。
dispatchMessage方法中,message中的callback是一个Runnable对象,如果callback不为空,则直接调用callback的run方法,否则判断Handler自己的mCallback是否为null,mCallback在Handler构造方法中初始化,在主线程中直接通过无参构造方法new出来的为null,所以会直接执行后面的handleMessage()方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); //Msg中的Runnable是否为null, callback在message的构造方法中初始化或者时候使用handler.post(Runnable)时才不为null
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//mCallback是一个callback对象,通过无参构造函数创建出来的handler该属性为null,所以不执行
return;
}
}
handleMessage(msg); //最终执行这里
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
Handler处理消息
最后调用handleMessage(Message)来处理消息,整个Handler机制的流程就结束了。
总结
Handler sendMessage发送消息到消息队列MessageQueue, 然后looper调用自己的loop方法轮寻MessageQueue里面的每一个Message。当Message达到了可以执行的时候就开始执行,执行后调用Message绑定的Hander来处理消息。
整体流程如下图
2.Handler中的难点问题
线程同步问题
Handler是用于线程之间通信的,但是它产生的根本不只是用于UI处理,而更多的是handler是真个app通信的框架,可以在ActivityThread里面感受到,整个app都是用它来进行线程见的协调。Handler是如何保证自己的线程安全的呢????
Handler机制里面最主要的类是MessageQueue,这个类是所有Message的存储仓库,消息的管理其实就两点:1.消息入库(enqueueMessage),2.消息出库(next)。所以只要在进出口确保线程安全就可以了。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) { //msg必须有绑定的Handler,否则不允许入列
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) { //当前的msg是否已经有其它Handler在使用
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) { //添加同步锁,保证在同一时刻只有一个Msg插入到MessageQueue中
if (mQuitting) { //当前的Thread时候已经被销毁
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", 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;
}
synchronized锁是一个内置锁,也就是由系统控制锁的lock unlock时机。
sychronized(this) 说明对所有调用MessageQueue对象的线程来说,他们都是互斥的,然而在我们Handler里面,一个线程是对应着一个唯一的Looper对象,然而Looper中又只有一个唯一的MessageQueue,所以我们主线程就只有一个MessageQueue对象,也就是说,所有的子线程向主线程发送消息的时候,主线程一次都只会处理一个消息,其它都需要等待,这样消息队列就不会出现混乱。
next函数
Message next() {
//上面代码省略.......
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) { //读取消息时加锁,锁仍然是MessageQueue对象
// 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);
} //锁结束
//省略 后面代码........
}
enqueueMessage 和 next 函数,它们都使用了synchronized(this), 保证next函数和enqueueMessage函数能够实现互斥,保证多线程访问的时候messageQueue的有序进行
消息机制之同步屏障
同步屏障,view绘制中用 同步屏障
在Handler机制中,线程的消息都是放在同一个MessageQueue里面,取消息的时候是互斥取消息,而且只能从头部取消息,而添加消息是按照消息的执行的先后顺序进行排序的。这时候存在一个问题,同一个时间范围内的消息,如果它是需要立刻执行的,怎么处理?? 按照常规的方法,我们需要等待队列轮寻到这条消息的时候才能执行,那就不符合需求了。所以需要给这条消息开一个绿色通道,这个绿色通道就是同步屏障的概念。
同步屏障是什么?
屏障字面意思就是阻碍的意思,同步屏障就是阻碍同步消息,只让异步消息通过。
如何开启同步屏障?
/**
* @hide
*/
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++;
//在消息池获取msg
final Message msg = Message.obtain();
msg.markInUse();
//就是这里!!!!! 初始化msg对象的时候,并没有给target赋值,因此target == null
msg.when = when;
msg.arg1 = token;
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;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p; //如果prev不为null,执行顺序就是prev -> msg -> p
prev.next = msg;
} else {
msg.next = p; //如果prev为null,执行顺序就是msg-> p
mMessages = msg;
}
return token;
}
}
可以看到,Message对象初始化的时候并没有给target赋值,因此 target == null的来源就找到了。一条target == null的消息就进入了消息队列
那么开启了同步屏障之后,所谓的异步消息又是如何被处理的呢??
Handler消息机制,消息最终处理是在消息轮寻器Looper#loop()中,而loop()循环中会调用MessageQueue#next从消息队列中取出消息。
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
//如果nextPollTimeoutMillis=-1, 一直阻塞不会超时
//如果nextPollTimeoutMillis=0, 不会阻塞,直接返回
//如果nextPollTimeoutMillis>0, 最长阻塞nextPollTimeoutMillis毫秒(超时)
// 如果期间有程序唤醒会立即返回
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; //当前链表的头节点
//关键点!!!!!!!!!!!!!! 如果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());
}
if (msg != null) {
//如果有消息需要处理,先判断时间有没有到,如果没有到的话设置一下阻塞时间,场景如常用的postDelay
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
//计算出离执行时间还要多久,然后赋值给nextPollTimeoutMillis
//表示nativePollOnce方法要等待nextPollTimeoutMillils时长后返回
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;
}
// 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(TAG, "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;
}
}
从上面就可以看出,当消息队列开启同步屏障的时候(即标识为msg.target == null),消息机制在处理消息的时候有限处理异步消息,这样同步屏障就起到了一种过滤和优先级的作用。
如上图所示,在消息队列中有同步消息和异步消息(黄色部分)以及一道墙---同步屏障(红色部分)。有了同步屏障的存在,msg_2和msg_M这两个异步消息就可以优先处理,而后面的msg_3等同步消息则不会被处理。那么这些同步消息什么时候被处理??? 就需要先移除这个同步屏障removeSyncBarrier
同步屏障应用场景
更新View时相关的消息即为异步消息,需要优先处理
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //开启同步屏障
//发送异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
postCallback最终走到
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);
}
}
}
这样就开启了同步屏障,并且发送了异步消息,这样系统就会有限处理这些异步消息。
最后,在处理完成后需要移除同步屏障
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); //移除同步屏障
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
一个线程有几个Handler
一个线程可以有n个Handler,可以new很多个,没有限制。
一个线程可以有几个Looper
一个线程只允许有一个looper,在子线程中创建looper的方法Looper.prepare 创建的looper对象保存在当前线程的ThreadLocal的ThreadLocalMap中(threadlocal, looper)键值对的形式存储下来。
同一个线程再次调用prepare时会抛出异常,并且map中存储时对于key threadlocal只有唯一的一个looper与之对应
Handler内存泄漏原因?为什么其它内部类没有说过这个问题
在java中非静态内部类默认可以访问外部类的所有变量和方法,因为非静态内部类持有了外部类的引用。还有匿名内部类
当我们在Activity中实现一个非静态Handler内部类,来处理一些延时事件,这种情况下就会出现内存泄漏的情况
当Activity销毁时,Handler还有延迟消息没有处理完,这时候因为Handler持有activity的引用,导致activity无法被回收,造成内存泄漏
//匿名内部类
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//非静态内部类
protected class AppHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// TODO: 2019/4/30
}
}
}
解决方法:
1.在activity销毁时,清空Handler中正在执行或未执行的Callback和Message
// 清空消息队列,移除对外部类的引用
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
//Handler源码中removeCallbacksAndMessages()注释含义
/**
* Remove any pending posts of callbacks and sent messages whose
* <var>obj</var> is <var>token</var>. If <var>token</var> is null,
* all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
2.声明为静态内部类,静态内部类不会持有外部类的引用,所以不会影响GC时activity的回收,然后在静态内部类中手动持有activity的弱引用,这样gc的时候即使被持有也会被回收
private static class AppHandler extends Handler {
//弱引用,在垃圾回收时,被回收
WeakReference<Activity> activity;
AppHandler(Activity activity){
this.activity=new WeakReference<Activity>(activity);
}
public void handleMessage(Message message){
switch (message.what){
//todo
}
}
}
3.即使内存泄漏了,在handler处理完后,下次GC时也会回收本次未被回收的内存
其它内部类中一般不会有延时的操作,所以没有遇到过内存泄漏的问题
主线程中可以直接new Handler, 子线程中如果想new Handler需要做哪些准备
1.因为主线程在ActivityThread的main函数中已经做了prepare,并且主线程的MessageQueue是不允许退出的
2.子线程中new 一个handler之前,需要Looper.prepare 这里面会创建一个looper对象,并将这个looper对象和当前子线程绑定
Looper.loop
Looper.quitSafely
子线程中处理完了消息就要调用quit 来跳出loop循环
Loop死循环为什么不会导致应用卡死
应用卡死也就是ANR的原因有两点:5s内没有响应输入的事件,比如按键或者屏幕触摸等,2.广播接收器处理超时 10s内没完成
首先我们需要知道,每一个应用都有一个属于自己的虚拟机,也就是说每个应用都有自己的Main函数,这个main函数就是ActivityThread.java中的main函数
为什么每个应用都有自己的main函数?
当我们在launcher界面开启一个app时,系统会用zygote给我们分配一个虚拟机,应用就运行在这个虚拟机上,之后执行的就是ActivityThread的main函数,在main函数中创建主线程的Looper对象
之后就Looper.loop一直轮寻整个主线程的消息
当MessageQueue中没有消息时,会阻塞在queue.next(),在next()函数中阻塞在nativePollOnce(ptr, nextPollTimeoutMillis)
这时不会导致ANR,这里就涉及到Linux pipe/epoll nativePollOnce()被阻塞时,主线程会释放CPU资源,进入休眠状态. 直到下个消息到达或者有事务发生,会通过pipe管道写入数据来唤醒主线程工作,就可以继续工作了.
这里主线程进入休眠状态和死循环是有区别的.
死循环是指主线程死锁在这里,一直执行某一块代码,无法再响应其他事件.
休眠状态是指在内核状态里,主线程被挂起,线程状态转移到休眠状
很多线程有很多Handler往MessagQueue添加数据,MessageQueue如何确保线程安全的
MessageQueue队列入队enqueueMessage和出队next都使用了同步锁 synchronized,并且锁对象是同一个 this也就是当前的MessageQueue对象
所以首先 入队和出队 不会同一时间发生,然后就是多个线程同时enqueueMessage时也不会出问题
使用Message时该如何创建它
使用Message的obtain方法,因为可以检查是否有可以复用的Message,避免过多的创建、销毁Message对象达到优化内存和性能的目的
并且obtain方法内也添加了同步锁,保证了线程安全
HandlerThread存在的意义
HandlerThread是Thread的子类,就是一个线程,只是它在自己的线程里面帮我们创建了Looper
优点:
1.使用方便,方便初始化,方便获取线程looper, 在HandlerThread的run方法中做了prepare, 获取looper对象,和loop()的操作,不需要自己操作
2.保证了线程安全
用法:
public class MainActivity extends AppCompatActivity {
private HandlerThread myHandlerThread ;
private Handler handler ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个线程,线程名字:handler-thread
myHandlerThread = new HandlerThread( "handler-thread") ; //这里就避免自己new thread并且获取looper对象更容易
//开启一个线程
myHandlerThread.start();
//在这个线程中创建一个handler对象
handler = new Handler( myHandlerThread.getLooper() ){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作
Log.d( "handler " , "消息: " + msg.what + " 线程: " + Thread.currentThread().getName() ) ;
}
};
//在主线程给handler发送消息
handler.sendEmptyMessage( 1 ) ;
new Thread(new Runnable() {
@Override
public void run() {
//在子线程给handler发送数据
handler.sendEmptyMessage( 2 ) ;
}
}).start() ;
}
@Override
protected void onDestroy() {
super.onDestroy();
//释放资源
myHandlerThread.quit() ;
}
}