当前位置: 移动技术网 > IT编程>移动开发>Android > Android Handler原理

Android Handler原理

2018年08月18日  | 移动技术网IT编程  | 我要评论

活血镇痛胶囊,木棉皇后,鲁嚓阁

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

      

 

每个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去处理消息。

 

 

 

 

  

主要是下面四只文件:

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

 

 

一个线程只有一个消息循环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所关联的线程上被取出和处理的.

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网