sending message to a Handler on a dead thread

本文探讨了如何避免Handler在关联的线程停止时抛出错误,提供了解决方案,包括使用mainLooper与创建专用HandlerThread。重点介绍了两种修复方法:一是通过Handler.getMainLooper()确保与主线程关联,二是创建独立线程并管理其生命周期。

Each Handler has a Looper, and a Looper is associated with a Thread (usually a HandlerThread). The general problem is when a Handler becomes associated with thread that stops running. If someone tries to use the Handler, it will fail with the message "sending message to a Handler on a dead thread".

If you just do new Handler() it becomes associated with the current thread (rather, it becomes associated with the Looper associated w/ the current thread). If you do this on a thread that that stops (such as the worker thread for an IntentService) you'll have the issue. The problem of course isn't limited to this root cause, it can happen in any number of ways.

Any easy fix is to construct your Handler like,

Handler h = new Handler(Looper.getMainLooper());

This associates the Handler with the main looper, or the main application thread which will never die (good for things like callbacks, but not for any blocking work obviously). Another more complex fix is to create a dedicated thread for the Handler,

HandlerThread ht = new HandlerThread(getClass().getName());
ht.start();
Handler handler = new Handler(ht.getLooper());

Note that you need to explicitly quit() the HandlerThread when you are done with the associated Handler.

Share

Follow

boolean enqueueMessage(Message msg, long when) { 647 if (msg.target == null) { 648 throw new IllegalArgumentException("Message must have a target."); 649 } 650 651 //#ifndef OPLUS_EXTENSION_HOOK 652 // Chucheng.Ye@ANDROID.RESCONTROL.2024/07/19,add for ocd 653 mMessageQueueExt.hookEnqueueMessage(msg.target, msg, when); 654 //#endif /*OPLUS_EXTENSION_HOOK*/ 655 656 synchronized (this) { 657 if (msg.isInUse()) { 658 throw new IllegalStateException(msg + " This message is already in use."); 659 } 660 661 if (mQuitting) { 662 IllegalStateException e = new IllegalStateException( 663 msg.target + " sending message to a Handler on a dead thread"); 664 Log.w(TAG, e.getMessage(), e); 665 msg.recycle(); 666 return false; 667 } 668 669 msg.markInUse(); 670 msg.when = when; 671 Message p = mMessages; 672 boolean needWake; 673 if (p == null || when == 0 || when < p.when) { 674 // New head, wake up the event queue if blocked. 675 msg.next = p; 676 mMessages = msg; 677 needWake = mBlocked; 678 if (p == null) { 679 mLast = mMessages; 680 } 681 } else { 682 // Message is to be inserted at tail or middle of queue. Usually we don't have to 683 // wake up the event queue unless there is a barrier at the head of the queue and 684 // the message is the earliest asynchronous message in the queue. 685 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 686 687 // For readability, we split this portion of the function into two blocks based on 688 // whether tail tracking is enabled. This has a minor implication for the case 689 // where tail tracking is disabled. See the comment below. 690 if (Flags.messageQueueTailTracking()) { 691 if (when >= mLast.when) { 692 needWake = needWake && mAsyncMessageCount == 0; 693 msg.next = null; 694 mLast.next = msg; 695 mLast = msg; 696 } else { 697 // Inserted within the middle of the queue. 698 Message prev; 699 //#ifdef OPLUS_BUG_STABILITY 700 //Haoran.Zhang 2017/07/20, Add for print log when message queue is too long,see bug 1045234 701 int msgCount = 0; 702 //#endif /*OPLUS_BUG_STABILITY*/ 703 for (;;) { 704 prev = p; 705 p = p.next; 706 if (p == null || when < p.when) { 707 break; 708 } 709 if (needWake && p.isAsynchronous()) { 710 needWake = false; 711 } 712 //#ifdef OPLUS_BUG_STABILITY 713 //Haoran.Zhang 2017/07/20, Add for print log when message queue is too long,see bug 1045234 714 //Weitao.Chen 2023/06/08, Modify for correcting the head message 715 ++msgCount; 716 if (msgCount >= 10000 && (msgCount % 10000 == 0)) { 717 Log.i(TAG, "searched " + msgCount + " messages, recent msg is " + p + " uid=" + p.workSourceUid 718 + ", head message is " + mMessages + " uid=" + mMessages.workSourceUid); 719 } 720 //#endif /*OPLUS_BUG_STABILITY*/ 721 } 722 //#ifdef OPLUS_BUG_STABILITY 723 //Daibo.Le 2023/09/12, Add for checking blocked barrier 724 mMessageQueueExt.checkBlockedBarrier(mMessages, msgCount); 725 //#endif /*OPLUS_BUG_STABILITY*/ 726 if (p == null) { 727 /* Inserting at tail of queue */ 728 mLast = msg; 729 } 730 msg.next = p; // invariant: p == prev.next 731 prev.next = msg; 732 } 733 } else { 734 Message prev; 735 //#ifdef OPLUS_BUG_STABILITY 736 //Haoran.Zhang 2017/07/20, Add for print log when message queue is too long,see bug 1045234 737 int msgCount = 0; 738 //#endif /*OPLUS_BUG_STABILITY*/ 739 for (;;) { 740 prev = p; 741 p = p.next; 742 if (p == null || when < p.when) { 743 break; 744 } 745 if (needWake && p.isAsynchronous()) { 746 needWake = false; 747 } 748 //#ifdef OPLUS_BUG_STABILITY 749 //Haoran.Zhang 2017/07/20, Add for print log when message queue is too long,see bug 1045234 750 //Weitao.Chen 2023/06/08, Modify for correcting the head message 751 ++msgCount; 752 if (msgCount >= 10000 && (msgCount % 10000 == 0)) { 753 Log.i(TAG, "searched " + msgCount + " messages, recent msg is " + p + " head message is " + mMessages); 754 } 755 //#endif /*OPLUS_BUG_STABILITY*/ 756 } 757 //#ifdef OPLUS_BUG_STABILITY 758 //Daibo.Le 2023/09/12, Add for checking blocked barrier 759 mMessageQueueExt.checkBlockedBarrier(mMessages, msgCount); 760 //#endif /*OPLUS_BUG_STABILITY*/ 761 msg.next = p; // invariant: p == prev.next 762 prev.next = msg; 763 764 /* 765 * If this block is executing then we have a build without tail tracking - 766 * specifically: Flags.messageQueueTailTracking() == false. This is determined 767 * at build time so the flag won't change on us during runtime. 768 * 769 * Since we don't want to pepper the code with extra checks, we only check 770 * for tail tracking when we might use mLast. Otherwise, we continue to update 771 * mLast as the tail of the list. 772 * 773 * In this case however we are not maintaining mLast correctly. Since we never 774 * use it, this is fine. However, we run the risk of leaking a reference. 775 * So set mLast to null in this case to avoid any Message leaks. The other 776 * sites will never use the value so we are safe against null pointer derefs. 777 */ 778 mLast = null; 779 } 780 } 781 782 if (msg.isAsynchronous()) { 783 mAsyncMessageCount++; 784 } 785 786 // We can assume mPtr != 0 because mQuitting is false. 787 if (needWake) { 788 nativeWake(mPtr); 789 } 790 } 791 return true; 792 }逐条解释一下这个方法的代码,要求尽量详细
最新发布
11-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值