O Handler é um mecanismo de retorno de chamada assíncrono fornecido pelo Android. Ele realiza principalmente a comunicação entre threads de mensagens. Então surge a pergunta. Por que precisamos do Handler? Há dois motivos principais. Um é evitar operações demoradas que bloqueiam o thread principal ( incluindo solicitações de rede). IU travada ou ANR, o sistema Android exige que o usuário coloque essas operações no subthread, 2 O Android também exige que a IU não possa ser atualizada no subthread (estimado com base em problemas de segurança do thread ), isso requer um mecanismo, no sub-thread A mensagem é passada para o thread principal no thread, então há um Handler.
Para implementar o callback assíncrono, não basta ter o Handler sozinho. O Android também fornece Looper, Message e MessageQueue. Essas classes juntas realizam a função de callback assíncrono. Normalmente, instanciamos um objeto Handler mHandler diretamente na Activity, enviamos uma mensagem através de mHandler na thread filha, e então recebemos o método de processamento no método callback passado ao instanciar o Handler. fio. Portanto, começamos a instanciar o Handler para uma análise aprofundada.
1, comece a instanciar o Handler
1,在主线程实例化Handler
private Handler mHandler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
return false;
}
});
2,进入Handler内部实现,到了最终的构造方法中
public Handler(@Nullable Callback callback, boolean async) {
...
mLooper = Looper.myLooper();//取出保存好的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//取出Looper中的消息队列
mCallback = callback; //后面处理消息的回调
mAsynchronous = async;
}
3,取出保存好的Looper的过程
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
4,ThreadLocal是什么,起的作用是什么?具体的看下ThreadLocal中set/get()的实现
ThreadLocal.java
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public void set(T value) {
Thread t = Thread.currentThread();//当前线程
ThreadLocalMap map = getMap(t);//得到线程中的一个变量,作用类似于HashMap,可以通过k-v保存数据
if (map != null)
map.set(this, value); //map以ThreadLocal为key,以Looper为value
else
createMap(t, value); //创建一个以ThreadLocal为key,以Looper为value的map给thread
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//取出map中的value,也就是looper
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
所以,Looper中的sThreadLocal明着像是一个保存looper的容器,但实际却是自己为key,looper为value,保存在线程Thread中的map中
2. Depois de instanciado o Handler, vemos que o Looper e o MessageQueue são retirados internamente, pelo que é necessário saber como estes são gerados
1,在主线程中取出来的,那肯定是在主线程实例的,而且是在主线程(ActivityThread)刚启动的时候
ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();//重点1
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);//这里之前详细分析过了,主要为了application/activity的创建和启动
...
Looper.loop();//重点2
throw new RuntimeException("Main thread loop unexpectedly exited");//抛异常, 主线程的loop出乎意料的退出了
}
2,重点1,Looper是如何产生的?
Looper.java
public static void prepareMainLooper() {
prepare(false);//关键语句,实例一个Looper,并保存
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();//实例化的Looper赋给sMainLooper
}
}
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));//通过threadLocad保存new出来的Looper
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//取出来
}
3,重点2 Looper是如何工作的?
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block 官方注解:可能阻塞,后续分析
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
...
}
}
简化以后就很明了了,loop()中取出之前实例好的looper,并取出looper中的消息队列queue,开启死循环,不停的执行消息队列取消息操作,
message.target是私有变量handler
Handler.java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//一般常见于使用handler.postXX(Runnable)发送的消息
handleCallback(msg);
} else {
if (mCallback != null) {这是之前实例化Handler传进去的回调监听类
if (mCallback.handleMessage(msg)) {//回调类的处理方法,实际在activity上,这样就把消息队列的消息传到主线程上了
return;
}
}
handleMessage(msg);//如果实例化Handler未传入回调类,则必须重新Handler本身的HandleMessage()方法,就是这个方法,同样的,把消息传到主线程上了
}
}
小结:通过查看Looper的实例化和Looper.loop()的调用,我们清楚的看到了消息的处理流程,
loop()依次从messageQueue中取出message,然后从message中取出handler去分配处理消息。
3. Agora que a mensagem foi retirada da fila de mensagens, deve haver um processo de colocar a mensagem na fila de mensagens
1,通过handler发送message的方法有2类,一种是send->Message系列,一种是post->Runnable系统
方法中带Message参数
sendMessage()//常用
sendMessageDelayed()//延迟接收的消息
sendMessageAtTime()//准确时间接收的消息
sendMessageAtFrontQueue()//见名知义,放到消息队列最前面,也就是马上执行的消息
sendEmptyMessage()//空消息
sendEmptyMessageAtTime()
sendEmptyMessageDelayed()
方法中带Runnable参数,通过getPostMessage()生成Message,runnable参数传入到message中(处理消息时使用此回调)
post()
postDelayed()
postAtTime()
postAtFrontOfQueue()
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
上面所有发送消息的方法,最终都是通过sendMessageAtTime(Message msg, long uptimeMillis)来发送的(方法千千万,最终汇总),uptimeMillis为处理消息的时间
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//这是Looper中的消息队列
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;//this就是当前的handler,处理消息时就是用的msg中的target
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//最终,handler把消息送到了消息队列中,然后消息队列进行入队操作
}
4. Bata os tambores e passe as flores, a mensagem finalmente será enviada para a fila de mensagens
0,在消息message进入消息队列messagequeue之前,我们需要对Message和MessageQueue的基本结构有初步的了解,方便了解入队的整个过程
Message:有个when字段,表示当前消息处理的时间,同样的,message关联指向了另一个message,字段名为next,所以,整个Message可以组成一个链表结构
MessageQueue:消息队列管理保存着消息,因为Message可以组成一个链表结构,所以MessageQueue只需要持有一个Message对象就能完成对Message的保存和管理,
因为消息队列有处理时间的要求,所以消息队列持有的头消息必定是最早处理的(when最小),所以在入队的过程就必然需要有对时间的比较。
1,enqueue的就是入队的意思
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.markInUse();
msg.when = 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; //头消息变成msg的next消息,这样就当前消息变成了头消息,原先的头消息变成第二个消息对象
mMessages = msg; //msg赋值给消息对象持有的头消息
needWake = mBlocked; //不需要唤醒,这个变量后面再讨论
} else { //下面的操作是msg要插入到消息链表中间去
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;//临时变量
for (;;) {//死循环遍历消息链表,查找msg需要插入的位置
prev = p;//当前查找的消息放到prev上,第一次当然是消息队列持有的头消息
p = p.next;//取出下一个消息为p 此时 prev->p
if (p == null || when < p.when) {//如果下一个消息为空(到链表尾巴上了) 或者时间戳小于下一个消息的时间戳 则位置找到了
break;//跳出死循环,位置找到了,msg要插在p前面,此时prev->p,执行插入后期望的顺序为 prev->msg->p
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; //
prev.next = msg;//这2步实现的功能就是链表顺序变为 prev->msg->p 此时头消息还是mMessage,但msg已经到它的链表上了
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr); //有消息来了,底层唤醒Looper
}
}
return true;
}
2,这样就很明了了,发送的消息经过比较和插入,终于进入到消息链表中了,结合前面的Looper.loop(),这样,整个流程就清楚了。
Resumo: O processo geral é o seguinte: No estágio inicial da criação do thread principal (ActivithThread.man()), enquanto o Looper é criado, uma fila de mensagens MessageQueue é criada no método de construção do Looper e o Looper é chamado após main( ). loop(), loop() chamará o Messagequeue instanciado no Looper, obterá continuamente a Message por meio de queue.next() e, em seguida, agendará e processará a mensagem por meio do destino (ou seja, o Handler) definido pela mensagem , e também podemos usar a instância Uma série de métodos send/post do Handler otimizado para enviar mensagens para a fila de mensagens. Pegue uma castanha na realidade:
Enquanto a estação de metrô estiver funcionando normalmente, as máquinas que passaram na inspeção de segurança devem estar ligadas e funcionando. A estação de metrô pode ser comparada a ActivityThread, a máquina de inspeção de segurança é Looper e o equipamento de inspeção de segurança está funcionando continuamente ( chamando Looper.loop()). O equipamento de inspeção de segurança possui uma correia de transmissão ( MessgaQueue), cada bagagem (Message) deve ser colocada na correia transportadora, o processo de colocação é o send/post() do handler, após a bagagem é testada e não há problema, ela pode ser retirada da outra ponta (handler.dispatchMessage(message)), Se a operação handler.send/post() for executada em outro thread, quando a mensagem for recuperada e programado para processamento, ele já está no thread principal, que realiza o retorno de chamada assíncrono.
O princípio de funcionamento do Handler é mais ou menos como mostrado na figura
Desta forma, todo o fluxo de trabalho do Handler é resolvido.
Claro, quando se trata de loops infinitos, por que looper.loop() não causa bloqueio de thread devido a loops infinitos?
答案很简单,整个App因为主线程中loop.looper()的死循环而保持活动,如果跳出死循环,整个App会抛异常,
ActivityThread.main(){
...
Looper.loop();//重点2
throw new RuntimeException("Main thread loop unexpectedly exited");//抛异常, 主线程的loop出乎意料的退出了 这句话正常情况下不会被执行
}
而且,造成主线程堵塞是因为对Message处理的超时造成的,以之前举例说明,安检设备因为传输带不断循环而保持正常工作,一旦行李过重,用户从传送带上搬离行李过慢才会造成后续行李的卡住(各类事件不被处理,造成阻塞)。
同样的,在消息队列中没有消息时,主线程会进入休眠状态,即消息队列执行next()方式时,会根据下一个消息还有多久执行系统底层方法nativePollOnce()释放资源进入休眠状态
MessageQueue.next(){
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);//直到下条消息到达或者有事务发生,
}
而一旦有最新消息事件进入到消息队列时,一旦新事件需要马上执行或者到了执行时间的时间,会通过系统底层方法nativeWake()唤醒主线程进行工作
MessageQueue.enqueueMessage(){
...
if (needWake) {
nativeWake(mPtr);//通过往 pipe 管道写端写入数据来唤醒主线程工作,这里采用的 epoll 机制
}
}
O mecanismo sleep executado pela thread principal quando não há tarefas otimiza muito o desempenho, assim como no envio de mensagens, o uso de get é mais eficiente que as instâncias diretas.
1,Message.java
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*从全局池中返回一个新消息实例
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;//Message类内部也有一个消息头,相当于也有一个消息链表 头消息置于m
sPool = m.next; //下一个消息置为表头
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;//
return m;//返回当初的表头消息
}
}
return new Message();
}
这样的话也不用每次都实例消息,最大限度的提高效率。
Resumo: Como um mecanismo de retorno de chamada de mensagem, Handler envolve relativamente poucas classes associadas e a estrutura geral é relativamente clara, mas a lógica interna ainda é muito valiosa para aprender.