欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Handler原理

程序员文章站 2022-04-13 22:17:26
Android线程间的通信是使用消息机制来实现的。线程通过Looper建立自己的消息循环, 对应MessageQueue。 MessageQueue是FIFO的消息队列。Looper负责从MessageQueue中取出消息,并且分发到消息指定的目标Handler对象,由Handler对象对Messa ......

       android线程间的通信是使用消息机制来实现的。线程通过looper建立自己的消息循环, 对应messagequeue。 messagequeue是fifo的消息队列。looper负责从messagequeue中取出消息,并且分发到消息指定的目标handler对象,由handler对象对message进行处理。

      Android Handler原理

 

每个app都有自己对应的messagequeue.

每个线程有且最多只能有一个looper对象,它是一个threadlocal
一个线程对应一个looper(消息循环),一个messagequeue(消息队列)
looper对象的创建是通过prepare函数,而且每一个looper对象会和一个线程关联.
looper对象创建时会创建一个messagequeue,主线程默认会创建一个looper从而有messagequeue,其他线程默认是没有 messagequeue的不能接收message,如果需要接收message则需要通过prepare函数创建一个messagequeue。
looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行
loop函数从messagequeue中从前往后取出message,然后通过handler的dispatchmessage函数进行消息的处理(可见消息的处理是handler负责的),消息处理完了以后通过message对象的recycle函数放到message pool中,以便下次使用,通过pool的处理提供了一定的内存管理从而加速消息对象的获取
looper使一个线程变成looper线程。
looper是线程用来运行消息循环的。线程本身是没有消息循环的,需要在线程中调用prepare函数,然后调用loop去处理消息。

 Android Handler原理

 

 

Android Handler原理

 

  Android Handler原理

主要是下面四只文件:

frameworks\base\core\java\android\os\looper.java
frameworks\base\core\java\android\os\handler.java
frameworks\base\core\java\android\os\messagequeue.java
frameworks\base\core\java\android\os\message.java

/frameworks/base/core/java/android/os/handler.java

192 public handler(callback callback, boolean async) {
193 if (find_potential_leaks) {
194 final class<? extends handler> klass = getclass();
195 if ((klass.isanonymousclass() || klass.ismemberclass() || klass.islocalclass()) &&
196 (klass.getmodifiers() & modifier.static) == 0) {
197 log.w(tag, "the following handler class should be static or leaks might occur: " +
198 klass.getcanonicalname());
199 }
200 }
201
202 mlooper = looper.mylooper();
203 if (mlooper == null) {
204 throw new runtimeexception(
205 "can't create handler inside thread that has not called looper.prepare()");
206 }
207 mqueue = mlooper.mqueue;
208 mcallback = callback;
209 masynchronous = async;
210 }

 

/frameworks/base/core/java/android/os/messagequeue.java 

309 message next() {
310 // return here if the message loop has already quit and been disposed.
311 // this can happen if the application tries to restart a looper after quit
312 // which is not supported.
313 final long ptr = mptr;
314 if (ptr == 0) {
315 return null;
316 }
317
318 int pendingidlehandlercount = -1; // -1 only during first iteration
319 int nextpolltimeoutmillis = 0;
320 for (;;) {
321 if (nextpolltimeoutmillis != 0) {
322 binder.flushpendingcommands();
323 }
324
325 nativepollonce(ptr, nextpolltimeoutmillis);
326
327 synchronized (this) {
328 // try to retrieve the next message. return if found.
329 final long now = systemclock.uptimemillis();
330 message prevmsg = null;
331 message msg = mmessages;
332 if (msg != null && msg.target == null) {
333 // stalled by a barrier. find the next asynchronous message in the queue.
334 do {
335 prevmsg = msg;
336 msg = msg.next;
337 } while (msg != null && !msg.isasynchronous());
338 }
339 if (msg != null) {
340 if (now < msg.when) {
341 // next message is not ready. set a timeout to wake up when it is ready.
342 nextpolltimeoutmillis = (int) math.min(msg.when - now, integer.max_value);
343 } else {
344 // got a message.
345 mblocked = false;
346 if (prevmsg != null) {
347 prevmsg.next = msg.next;
348 } else {
349 mmessages = msg.next;
350 }
351 msg.next = null;
352 if (debug) log.v(tag, "returning message: " + msg);
353 msg.markinuse();
354 return msg;
355 }
356 } else {
357 // no more messages.
358 nextpolltimeoutmillis = -1;
359 }
360
361 // process the quit message now that all pending messages have been handled.
362 if (mquitting) {
363 dispose();
364 return null;
365 }
366
367 // if first time idle, then get the number of idlers to run.
368 // idle handles only run if the queue is empty or if the first message
369 // in the queue (possibly a barrier) is due to be handled in the future.
370 if (pendingidlehandlercount < 0
371 && (mmessages == null || now < mmessages.when)) {
372 pendingidlehandlercount = midlehandlers.size();
373 }
374 if (pendingidlehandlercount <= 0) {
375 // no idle handlers to run. loop and wait some more.
376 mblocked = true;
377 continue;
378 }
379
380 if (mpendingidlehandlers == null) {
381 mpendingidlehandlers = new idlehandler[math.max(pendingidlehandlercount, 4)];
382 }
383 mpendingidlehandlers = midlehandlers.toarray(mpendingidlehandlers);
384 }
385
386 // run the idle handlers.
387 // we only ever reach this code block during the first iteration.
388 for (int i = 0; i < pendingidlehandlercount; i++) {
389 final idlehandler idler = mpendingidlehandlers[i];
390 mpendingidlehandlers[i] = null; // release the reference to the handler
391
392 boolean keep = false;
393 try {
394 keep = idler.queueidle();
395 } catch (throwable t) {
396 log.wtf(tag, "idlehandler threw exception", t);
397 }
398
399 if (!keep) {
400 synchronized (this) {
401 midlehandlers.remove(idler);
402 }
403 }
404 }
405
406 // reset the idle handler count to 0 so we do not run them again.
407 pendingidlehandlercount = 0;
408
409 // while calling an idle handler, a new message could have been delivered
410 // so go back and look again for a pending message without waiting.
411 nextpolltimeoutmillis = 0;
412 }
413 }

 

535 boolean enqueuemessage(message msg, long when) {
536 if (msg.target == null) {
537 throw new illegalargumentexception("message must have a target.");
538 }
539 if (msg.isinuse()) {
540 throw new illegalstateexception(msg + " this message is already in use.");
541 }
542
543 synchronized (this) {
544 if (mquitting) {
545 illegalstateexception e = new illegalstateexception(
546 msg.target + " sending message to a handler on a dead thread");
547 log.w(tag, e.getmessage(), e);
548 msg.recycle();
549 return false;
550 }
551
552 msg.markinuse();
553 msg.when = when;
554 message p = mmessages;
555 boolean needwake;
556 if (p == null || when == 0 || when < p.when) {
557 // new head, wake up the event queue if blocked.
558 msg.next = p;
559 mmessages = msg;
560 needwake = mblocked;
561 } else {
562 // inserted within the middle of the queue. usually we don't have to wake
563 // up the event queue unless there is a barrier at the head of the queue
564 // and the message is the earliest asynchronous message in the queue.
565 needwake = mblocked && p.target == null && msg.isasynchronous();
566 message prev;
567 for (;;) {
568 prev = p;
569 p = p.next;
570 if (p == null || when < p.when) {
571 break;
572 }
573 if (needwake && p.isasynchronous()) {
574 needwake = false;
575 }
576 }
577 msg.next = p; // invariant: p == prev.next
578 prev.next = msg;
579 }
580
581 // we can assume mptr != 0 because mquitting is false.
582 if (needwake) {
583 nativewake(mptr);
584 }
585 }
586 return true;
587 }

 

/frameworks/base/core/java/android/os/looper.java

129 public static void loop() {
130 final looper me = mylooper();
131 if (me == null) {
132 throw new runtimeexception("no looper; looper.prepare() wasn't called on this thread.");
133 }
134 final messagequeue queue = me.mqueue;
135
136 // make sure the identity of this thread is that of the local process,
137 // and keep track of what that identity token actually is.
138 binder.clearcallingidentity();
139 final long ident = binder.clearcallingidentity();
140
141 for (;;) {
142 message msg = queue.next(); // might block
143 if (msg == null) {
144 // no message indicates that the message queue is quitting.
145 return;
146 }
147
148 // this must be in a local variable, in case a ui event sets the logger
149 final printer logging = me.mlogging;
150 if (logging != null) {
151 logging.println(">>>>> dispatching to " + msg.target + " " +
152 msg.callback + ": " + msg.what);
153 }
154
155 final long slowdispatchthresholdms = me.mslowdispatchthresholdms;
156
157 final long tracetag = me.mtracetag;
158 if (tracetag != 0 && trace.istagenabled(tracetag)) {
159 trace.tracebegin(tracetag, msg.target.gettracename(msg));
160 }
161 final long start = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis();
162 final long end;
163 try {
164 msg.target.dispatchmessage(msg);
165 end = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis();
166 } finally {
167 if (tracetag != 0) {
168 trace.traceend(tracetag);
169 }
170 }
171 if (slowdispatchthresholdms > 0) {
172 final long time = end - start;
173 if (time > slowdispatchthresholdms) {
174 slog.w(tag, "dispatch took " + time + "ms on "
175 + thread.currentthread().getname() + ", h=" +
176 msg.target + " cb=" + msg.callback + " msg=" + msg.what);
177 }
178 }
179
180 if (logging != null) {
181 logging.println("<<<<< finished to " + msg.target + " " + msg.callback);
182 }
183
184 // make sure that during the course of dispatching the
185 // identity of the thread wasn't corrupted.
186 final long newident = binder.clearcallingidentity();
187 if (ident != newident) {
188 log.wtf(tag, "thread identity changed from 0x"
189 + long.tohexstring(ident) + " to 0x"
190 + long.tohexstring(newident) + " while dispatching to "
191 + msg.target.getclass().getname() + " "
192 + msg.callback + " what=" + msg.what);
193 }
194
195 msg.recycleunchecked();
196 }
197 }

 

1. handler可以在任意线程发送消息,这些消息会被添加到关联的message queue上.

2. handler是在它关联的looper线程中处理消息的.

3. 开发者需要重写handler的handlemessage().

 

 message structure

Android Handler原理

 

 

一个线程只有一个消息循环looper和一个消息队列;但是可以有多个handler,那么如何区分消息发送给谁处理呢?
每个消息中都有target对应的handler对象
将消息压入消息队列: message对象的target字段关联了哪个线程的消息队列, 这个消息就会被压入哪个线程的消息队列中.
调用handler对象的方法入队的message(最终都会调用enqueuemessage), 其target属性会被赋值为这个handler对象.
调用handler类中以send开头的方法可以将message对象压入消息队列中;
调用handler类中以post开头的方法可以将一个runnable对象包装在一个message对象中, 然后再压入消息队列, 此时入队的message其callback字段不为null, 值就是这个runnable对象.
调用message对象的sendtotarget()方法可以将其本身压入与其target字段(即handler对象)所关联的消息队列 中. 
从消息队列中取出消息并处理消息: 所有在消息队列中的消息, 都具有target字段. 消息是在target所关联的线程上被取出和处理的.