不懂代码可以做网站吗,韩国女排出线,nodejs 网站开发,cloudflare wordpressHandle是进程内部, 线程之间的通信机制.
handle主要接受子线程发送的数据, 并用此数据配合主线程更新UI
handle可以分发Message对象和Runnable对象到主线程中, 每个handle实例, 都会绑定到创建他的线程中, 它有两个作用,:
(1) 安排消息在某个主线程中某个地方执行
(2) 安排…Handle是进程内部, 线程之间的通信机制.
handle主要接受子线程发送的数据, 并用此数据配合主线程更新UI
handle可以分发Message对象和Runnable对象到主线程中, 每个handle实例, 都会绑定到创建他的线程中, 它有两个作用,:
(1) 安排消息在某个主线程中某个地方执行
(2) 安排一个动作在不同的线程中执行
Handle, Lopper, MessegeQueue, Message的关系 handle机制中, 主要牵涉的类有如下四个, 它们分工明确, 但又互相作用
1. Message:消息
2. hanlder:消息的发起者
3. Lopper: 消息的遍历者
4.MessageQueue 消息队列 1.Loop类 public final class Looper {UnsupportedAppUsagestatic final ThreadLocalLooper sThreadLocal new ThreadLocalLooper();UnsupportedAppUsageprivate static Looper sMainLooper; // guarded by Looper.classprivate static Observer sObserver;UnsupportedAppUsagefinal MessageQueue mQueue;final Thread mThread;private boolean mInLoop;266 public static void loop() {
267 final Looper me myLooper();
268 if (me null) {
269 throw new RuntimeException(No Looper; Looper.prepare() wasnt called on this thread.);
270 }
271 if (me.mInLoop) {
272 Slog.w(TAG, Loop again would have the queued messages be executed
273 before this one completed.);
274 }
275
276 me.mInLoop true;
277
278 // Make sure the identity of this thread is that of the local process,
279 // and keep track of what that identity token actually is.
280 Binder.clearCallingIdentity();
281 final long ident Binder.clearCallingIdentity();
282
283 // Allow overriding a threshold with a system prop. e.g.
284 // adb shell setprop log.looper.1000.main.slow 1 stop start
285 final int thresholdOverride
286 SystemProperties.getInt(log.looper.
287 Process.myUid() .
288 Thread.currentThread().getName()
289 .slow, -1);
290
291 me.mSlowDeliveryDetected false;
292
293 for (;;) {
294 if (!loopOnce(me, ident, thresholdOverride)) {
295 return;
296 }
297 }
298 }330 private Looper(boolean quitAllowed) {
331 mQueue new MessageQueue(quitAllowed);
332 mThread Thread.currentThread();
333 } 创建Looper对象的时候同时创建了MessageQueue,并让Looper绑定当前线程。但我们从来不直接调用构造方法获取Looper对象而是使用Looper的prepare()方法
108 public static void prepare() {
109 prepare(true);
110 }
111
112 private static void prepare(boolean quitAllowed) {
113 if (sThreadLocal.get() ! null) {
114 throw new RuntimeException(Only one Looper may be created per thread);
115 }
116 sThreadLocal.set(new Looper(quitAllowed));
117 }
118 126 Deprecated
127 public static void prepareMainLooper() {
128 prepare(false);
129 synchronized (Looper.class) {
130 if (sMainLooper ! null) {
131 throw new IllegalStateException(The main Looper has already been prepared.);
132 }
133 sMainLooper myLooper();
134 }
135 }
prepare()使用ThreadLocal 保存当前Looper对象ThreadLocal 类可以对数据进行线程隔离保证了在当前线程只能获取当前线程的Looper对象同时prepare()保证当前线程有且只有一个Looper对象间接保证了一个线程只有一个MessageQueue对象
prepareMainLooper统在启动App时已经帮我们调用了
266 public static void loop() {
267 final Looper me myLooper();
268 if (me null) {
269 throw new RuntimeException(No Looper; Looper.prepare() wasnt called on this thread.);
270 }
271 if (me.mInLoop) {
272 Slog.w(TAG, Loop again would have the queued messages be executed
273 before this one completed.);
274 }
275
276 me.mInLoop true;
277
278 // Make sure the identity of this thread is that of the local process,
279 // and keep track of what that identity token actually is.
280 Binder.clearCallingIdentity();
281 final long ident Binder.clearCallingIdentity();
282
283 // Allow overriding a threshold with a system prop. e.g.
284 // adb shell setprop log.looper.1000.main.slow 1 stop start
285 final int thresholdOverride
286 SystemProperties.getInt(log.looper.
287 Process.myUid() .
288 Thread.currentThread().getName()
289 .slow, -1);
290
291 me.mSlowDeliveryDetected false;
292
293 for (;;) {
294 if (!loopOnce(me, ident, thresholdOverride)) {
295 return;
296 }
297 }
298 }
Lopper通过loop()开启无限循环通过MessageQueue的next()获取message对象。一旦获取就调用msg.target.dispatchMEssage(msg)将msg交给handler对象处理(msg.target是handler对象)
所以Looper.loop的作用就是从当前线程的MessageQueue从不断取出Message并调用其相关的回调方法。
2. handler类 创建Handler对象 得到当前线程的Looper对象并判断是否为空 让创建的Handler对象持有Looper、MessageQueu、Callback的引用 214 public Handler(Nullable Callback callback, boolean async) {
215 if (FIND_POTENTIAL_LEAKS) {
216 final Class? extends Handler klass getClass();
217 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())
218 (klass.getModifiers() Modifier.STATIC) 0) {
219 Log.w(TAG, The following Handler class should be static or leaks might occur:
220 klass.getCanonicalName());
221 }
222 }
223
224 mLooper Looper.myLooper();
225 if (mLooper null) {
226 throw new RuntimeException(
227 Cant create handler inside thread Thread.currentThread()
228 that has not called Looper.prepare());
229 }
230 mQueue mLooper.mQueue;
231 mCallback callback;
232 mAsynchronous async;
233 mIsShared false;
234 }
235 使用Handler发送消息主要有两种一种是sendXXXMessage方式还有一个postXXX方式不过两种方式最后都会调用到sendMessageDelayed方法 下面为sendMessage方式 发送消息将消息插入队列sendMessage-sendMessageDelayed-sendMessageAtTime-enqueueMessage这里会决定message是否为同步消息或者异步消息 727 public boolean sendMessageAtTime(NonNull Message msg, long uptimeMillis) {
728 MessageQueue queue mQueue;
729 if (queue null) {
730 RuntimeException e new RuntimeException(
731 this sendMessageAtTime() called with no mQueue);
732 Log.w(Looper, e.getMessage(), e);
733 return false;
734 }
735 return enqueueMessage(queue, msg, uptimeMillis);
736 } 778 private boolean enqueueMessage(NonNull MessageQueue queue, NonNull Message msg,
779 long uptimeMillis) {
780 msg.target this;
781 msg.workSourceUid ThreadLocalWorkSource.getUid();
782
783 if (mAsynchronous) {
784 msg.setAsynchronous(true);
785 }
786 return queue.enqueueMessage(msg, uptimeMillis);
787 } 549 boolean enqueueMessage(Message msg, long when) {
550 if (msg.target null) {
551 throw new IllegalArgumentException(Message must have a target.);
552 }
553
554 synchronized (this) {
// 一个message只能呢个发送一次
555 if (msg.isInUse()) {
556 throw new IllegalStateException(msg This message is already in use.);
557 }
558
559 if (mQuitting) {
560 IllegalStateException e new IllegalStateException(
561 msg.target sending message to a Handler on a dead thread);
562 Log.w(TAG, e.getMessage(), e);
563 msg.recycle();
564 return false;
565 }
566 // 标记message已经使用
567 msg.markInUse();
568 msg.when when;
// 拿到头部
569 Message p mMessages;
570 boolean needWake;
571 if (p null || when 0 || when p.when) {
572 // New head, wake up the event queue if blocked.
// 将消息插入到头部, 指向刚才拿到的消息
573 msg.next p;
574 mMessages msg;
575 needWake mBlocked;
576 } else {
// 根据需要把消息插入到消息队列的合适位置通常是调用xxxDelay方法延时发送消息
577 // Inserted within the middle of the queue. Usually we dont have to wake
578 // up the event queue unless there is a barrier at the head of the queue
579 // and the message is the earliest asynchronous message in the queue.
580 needWake mBlocked p.target null msg.isAsynchronous();
581 Message prev;
582 for (;;) {
583 prev p;
584 p p.next;
585 if (p null || when p.when) {
586 break;
587 }
588 if (needWake p.isAsynchronous()) {
589 needWake false;
590 }
591 }
592 msg.next p; // invariant: p prev.next
593 prev.next msg;
594 }
595
596 // We can assume mPtr ! 0 because mQuitting is false.
597 if (needWake) {
598 nativeWake(mPtr);
599 }
600 }
601 return true;
602 } //getPostMessage方法是两种发送消息的不同之处 Post这个方法我们发现也是将我们传入的参数封装成了一个消息只是这次是m.callback r,刚才是msg.whatwhat,至于Message的这些属性就不看了 434 public final boolean post(NonNull Runnable r) {
435 return sendMessageDelayed(getPostMessage(r), 0);
436 }943 private static Message getPostMessage(Runnable r) {
944 Message m Message.obtain();
945 m.callback r;
946 return m;
947 } post方法只是先调用了getPostMessage方法用Runnable去封装一个Message然后就调用了sendMessageDelayed把封装的Message加入到MessageQueue中。 所以使用handler发送消息的本质都是把Message加入到Handler中的MessageQueue中去 97 public void dispatchMessage(NonNull Message msg) {
98 if (msg.callback ! null) {
99 handleCallback(msg);
100 } else {
101 if (mCallback ! null) {
102 if (mCallback.handleMessage(msg)) {
103 return;
104 }
105 }
106 handleMessage(msg);
107 }
108 }
109 可以看出这个方法就是从MessageQueue中取出Message以后进行分发处理。 首先判断msg.callback是不是空其实msg.callback是一个Runnable对象是Handler.post方式传递进来的参数。而hanldeCallback就是调用的Runnable的run方法。 然后判断mCallback是否为空这是一个Handler.Callback的接口类型之前说了Handler有多个构造方法可以提供设置Callback如果这里不为空则调用它的hanldeMessage方法注意这个方法有返回值如果返回了true表示已经处理 不再调用Handler的handleMessage方法如果mCallback为空或者不为空但是它的handleMessage返回了false则会继续调用Handler的handleMessage方法该方法就是我们经常重写的那个方法。 3. MessageQueue 318 UnsupportedAppUsage
319 Message next() {
320 // Return here if the message loop has already quit and been disposed.
321 // This can happen if the application tries to restart a looper after quit
322 // which is not supported.
323 final long ptr mPtr;
324 if (ptr 0) {
325 return null;
326 }
327
328 int pendingIdleHandlerCount -1; // -1 only during first iteration
329 int nextPollTimeoutMillis 0;
330 for (;;) {
331 if (nextPollTimeoutMillis ! 0) {
332 Binder.flushPendingCommands();
333 }
334
335 nativePollOnce(ptr, nextPollTimeoutMillis);
336
337 synchronized (this) {
338 // Try to retrieve the next message. Return if found.
339 final long now SystemClock.uptimeMillis();
340 Message prevMsg null;
341 Message msg mMessages;
342 if (msg ! null msg.target null) {
343 // Stalled by a barrier. Find the next asynchronous message in the queue.
344 do {
345 prevMsg msg;
346 msg msg.next;
347 } while (msg ! null !msg.isAsynchronous());
348 }
349 if (msg ! null) {
350 if (now msg.when) {
351 // Next message is not ready. Set a timeout to wake up when it is ready.
352 nextPollTimeoutMillis (int) Math.min(msg.when - now, Integer.MAX_VALUE);
353 } else {
354 // Got a message.
355 mBlocked false;
356 if (prevMsg ! null) {
357 prevMsg.next msg.next;
358 } else {
359 mMessages msg.next;
360 }
361 msg.next null;
362 if (DEBUG) Log.v(TAG, Returning message: msg);
363 msg.markInUse();
364 return msg;
365 }
366 } else {
367 // No more messages.
368 nextPollTimeoutMillis -1;
369 }
370
371 // Process the quit message now that all pending messages have been handled.
372 if (mQuitting) {
373 dispose();
374 return null;
375 }
376
377 // If first time idle, then get the number of idlers to run.
378 // Idle handles only run if the queue is empty or if the first message
379 // in the queue (possibly a barrier) is due to be handled in the future.
380 if (pendingIdleHandlerCount 0
381 (mMessages null || now mMessages.when)) {
382 pendingIdleHandlerCount mIdleHandlers.size();
383 }
384 if (pendingIdleHandlerCount 0) {
385 // No idle handlers to run. Loop and wait some more.
386 mBlocked true;
387 continue;
388 }
389
390 if (mPendingIdleHandlers null) {
391 mPendingIdleHandlers new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
392 }
393 mPendingIdleHandlers mIdleHandlers.toArray(mPendingIdleHandlers);
394 }
395
396 // Run the idle handlers.
397 // We only ever reach this code block during the first iteration.
398 for (int i 0; i pendingIdleHandlerCount; i) {
399 final IdleHandler idler mPendingIdleHandlers[i];
400 mPendingIdleHandlers[i] null; // release the reference to the handler
401
402 boolean keep false;
403 try {
404 keep idler.queueIdle();
405 } catch (Throwable t) {
406 Log.wtf(TAG, IdleHandler threw exception, t);
407 }
408
409 if (!keep) {
410 synchronized (this) {
411 mIdleHandlers.remove(idler);
412 }
413 }
414 }
415
416 // Reset the idle handler count to 0 so we do not run them again.
417 pendingIdleHandlerCount 0;
418
419 // While calling an idle handler, a new message could have been delivered
420 // so go back and look again for a pending message without waiting.
421 nextPollTimeoutMillis 0;
422 }
423 } next方法中首先设置一个死循环然后调用nativePollOnce(ptr, nextPollTimeoutMillis)方法它是一个native方法用于阻塞MessageQueue主要是关注它的第二个参数nextPollTimeoutMillis有如下三种可能
如果nextPollTimeoutMillis-1一直阻塞不会超时。
如果nextPollTimeoutMillis0不会阻塞立即返回。
如果nextPollTimeoutMillis0最长阻塞nextPollTimeoutMillis毫秒(超时)如果其间有程序唤醒会立即返回。
我们先继续往下看开始nextPollTimeoutMillis为0也就是不会阻塞则继续往下这时候有三种情况
1.延时消息则直接算出目前需要延时的时间nextPollTimeoutMillis注意这时候并没有把消息返回而是继续往下设置mBlocked为true表示消息队列已阻塞并continue执行for循环体再次执行nativePollOnce方法这时候nextPollTimeoutMillis0则会导致MessageQueue休眠nextPollTimeoutMillis毫秒接着应该会走到情况2.
2.不是延时消息则设置mBlocked为false表示消息队列没有阻塞直接把消息返回且把消息出队。
3. 如果消息为空则调用位置nextPollTimeoutMillis为-1继续往下设置mBlocked为true表示消息队列已阻塞并continue继续for循环这时候调用nativePollOnce会一直阻塞且不会超时。
所以当消息队列为空时其实是调用本地方法nativePollOnce且第二个参数为-1它会导致当前线程阻塞且不会超时
4. Message
Message分为3种普通消息同步消息、屏障消息同步屏障和异步消息。我们通常使用的都是普通消息而屏障消息就是在消息队列中插入一个屏障在屏障之后的所有普通消息都会被挡着不能被处理。不过异步消息却例外屏障不会挡住异步消息
因此可以这样认为屏障消息就是为了确保异步消息的优先级设置了屏障后只能处理其后的异步消息同步消息会被挡住除非撤销屏障。
同步屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。
屏障消息和普通消息的区别是屏障消息没有tartget。
1.屏障的插队方法
屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。
public int postSyncBarrier() {
473 return postSyncBarrier(SystemClock.uptimeMillis());
474 }
475
476 private int postSyncBarrier(long when) {
477 // Enqueue a new sync barrier token.
478 // We dont need to wake the queue because the purpose of a barrier is to stall it.
479 synchronized (this) {
480 final int token mNextBarrierToken;
481 final Message msg Message.obtain();
482 msg.markInUse();
483 msg.when when;
484 msg.arg1 token;
485
486 Message prev null;
487 Message p mMessages;
488 if (when ! 0) {
489 while (p ! null p.when when) {
490 prev p;
491 p p.next;
492 }
493 }
494 if (prev ! null) { // invariant: p prev.next
495 msg.next p;
496 prev.next msg;
497 } else {
498 msg.next p;
499 mMessages msg;
500 }
501 return token;
502 }
503 }
504
屏障消息和普通消息的区别在于屏障没有tartget普通消息有target是因为它需要将消息分发给对应的target而屏障不需要被分发它就是用来挡住普通消息来保证异步消息优先处理的。屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置并且只会挡住它后面的同步消息的分发。postSyncBarrier返回一个int类型的数值通过这个数值可以撤销屏障。postSyncBarrier方法是私有的如果我们想调用它就得使用反射。插入普通消息会唤醒消息队列但是插入屏障不会。 2.屏障的工作原理
通过postSyncBarrier方法屏障就被插入到消息队列中了那么屏障是如何挡住普通消息只允许异步消息通过的呢我们知道MessageQueue是通过next方法来获取消息的。
通过messaQequeue中的next如果碰到屏障就遍历整个消息链表找到最近的一条异步消息在遍历的过程中只有异步消息才会被处理执行到 if (msg ! null){}中的代码。可以看到通过这种方式就挡住了所有的普通消息
3,同步消息还是异步消息的决定时间
Handler有几个构造方法可以传入async标志为true这样构造的Handler发送的消息就是异步消息。不过可以看到这些构造函数都是hide的正常我们是不能调用的不过利用反射机制可以使用hide方法。
/*** hide*/
public Handler(boolean async) {}/*** hide*/
public Handler(Callback callback, boolean async) { }/*** hide*/
public Handler(Looper looper, Callback callback, boolean async) {}
也可以直接调用message.setAsynchronous(true);来进行设置为异步消息
509 public void setAsynchronous(boolean async) {
510 if (async) {
511 flags | FLAG_ASYNCHRONOUS;
512 } else {
513 flags ~FLAG_ASYNCHRONOUS;
514 }
515 }
3.屏障的移除 移除屏障可以通过MessageQueue的removeSyncBarrier方法
517 public void removeSyncBarrier(int token) {
518 // Remove a sync barrier token from the queue.
519 // If the queue is no longer stalled by a barrier then wake it.
520 synchronized (this) {
521 Message prev null;
522 Message p mMessages;
523 while (p ! null (p.target ! null || p.arg1 ! token)) {
524 prev p;
525 p p.next;
526 }
527 if (p null) {
528 throw new IllegalStateException(The specified message queue synchronization
529 barrier token has not been posted or has already been removed.);
530 }
531 final boolean needWake;
532 if (prev ! null) {
533 prev.next p.next;
534 needWake false;
535 } else {
536 mMessages p.next;
537 needWake mMessages null || mMessages.target ! null;
538 }
539 p.recycleUnchecked();
540
541 // If the loop is quitting then it is already awake.
542 // We can assume mPtr ! 0 when mQuitting is false.
543 if (needWake !mQuitting) {
544 nativeWake(mPtr);
545 }
546 }
547 }
总结下Handler消息机制主要的四个类的功能
Message:信息的携带者持有了Handler存在MessageQueue中一个线程可以有多个Hanlder:消息的发起者发送Message以及消息处理的回调实现一个线程可以有多个Handler对象Looper:消息的遍历者从MessageQueue中循环取出Message进行处理一个线程最多只有一个MessageQueue:消息队列存放了Handler发送的消息供Looper循环取消息一个线程最多只有一个