เอกสารนี้แสดงวิธีระบุเทรดที่ไม่ตอบสนองในกลุ่ม ANR ดัมพ์ เทรดที่ไม่ตอบสนองจะแตกต่างกันไปตามประเภทของ ANR ดังที่แสดงใน
ประเภท ANR | ชุดข้อความที่ไม่ตอบสนอง |
---|---|
การจ่ายอินพุต | เทรดหลัก |
อินพุตของเอาต์พุตไม่มีหน้าต่างที่โฟกัสอยู่ | เทรดหลัก ANR ประเภทนี้มักไม่ได้เกิดจากการ ชุดข้อความ |
Broadcast Receiver (ซิงโครนัส) | ชุดข้อความกำลังทำงาน
onReceive()
นี่คือเทรดหลัก เว้นแต่ว่าตัวแฮนเดิลที่กำหนดเองในเทรดที่ไม่ใช่หลัก
ระบุโดยใช้
Context.registerReceiver |
Broadcast Receiver (อะซิงโครนัส) | ตรวจสอบโค้ดเพื่อดูว่าเทรดหรือ Thread Pool ใดรับผิดชอบ
ดำเนินการเพื่อประมวลผลการออกอากาศหลังจาก
goAsync
จะถูกเรียก |
หมดเวลาเรียกใช้บริการ | เทรดหลัก |
เริ่มบริการที่ทำงานอยู่เบื้องหน้า | เทรดหลัก |
ผู้ให้บริการเนื้อหาไม่ตอบสนอง | ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้
|
ไม่มีการตอบกลับ
onStartJob
หรือ
วันที่ onStopJob |
เทรดหลัก |
บางครั้งชุดข้อความไม่ตอบสนองเนื่องจากมีสาเหตุหลักของชุดข้อความอื่น หรือกระบวนการ ชุดข้อความไม่ตอบสนองได้เนื่องจากกำลังรอสิ่งต่อไปนี้
- ล็อกที่เทรดอื่นใช้งานอยู่
- การเรียกใช้ Binder ที่ช้าไปยังกระบวนการอื่น
สาเหตุที่พบบ่อยของชุดข้อความไม่ตอบสนอง
ต่อไปนี้คือสาเหตุที่พบบ่อยของชุดข้อความไม่ตอบสนอง
การเรียกใช้ Binder ที่ช้า
แม้ว่าการเรียกใช้ Binder ส่วนใหญ่จะรวดเร็ว แต่แท็กยาวๆ ก็อาจจะช้ามาก นี่คือ มีโอกาสสูงที่จะเกิดขึ้นเมื่ออุปกรณ์โหลด หรือชุดข้อความการตอบกลับของ Binder ช้า เช่น จากการช่วงชิงล็อก มีสายเรียกเข้าจำนวนมาก หรือฮาร์ดแวร์ Abstraction Layer (HAL) หมดเวลา
คุณแก้ไขปัญหานี้ได้โดยย้ายการเรียกใช้ Binder แบบซิงโครนัสไปยังเทรดในเบื้องหลัง หากเป็นไปได้ หากต้องมีการเรียกในเทรดหลัก ลองหาสาเหตุ การโทรช้า วิธีที่ดีที่สุดคือการติดตามจาก Perfetto
มองหา BinderProxy.transactNative
หรือ Binderproxy.transact
ในกลุ่ม
ซึ่งหมายความว่ามีการเรียก Binder หลังจากสองบรรทัดนี้ คุณจะเห็น
Binder API ที่เรียกใช้ ในตัวอย่างต่อไปนี้ การโทรคือ
IAccessibilityManager.addClient
main tid=123
...
android.os.BinderProxy.transactNative (Native method)
android.os.BinderProxy.transact (BinderProxy.java:568)
android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599)
...
การเรียกใช้ Binder ติดต่อกันหลายรายการ
การดำเนินการเรียกใช้ Binder ติดต่อกันหลายครั้งในลูปแคบๆ จะบล็อกเทรดได้ เป็นเวลานาน
I/O ที่ถูกบล็อก
ไม่บล็อก I/O ในเทรดหลัก นี่คือ Antipattern
การช่วงชิงล็อก
หากเทรดถูกบล็อกเมื่อได้รับการล็อก ก็อาจทำให้เกิด ANR ได้
ตัวอย่างต่อไปนี้แสดงให้เห็นว่าเทรดหลักถูกบล็อกเมื่อพยายามดึงข้อมูล ล็อก:
main (tid=1) Blocked
Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD
[...]
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412)
[...]
เทรดที่บล็อกกำลังส่งคำขอ HTTP เพื่อดาวน์โหลดวิดีโอ
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting
at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136)
at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711)
[...]
เฟรมราคาแพง
การแสดงภาพสิ่งต่างๆ มากเกินไปในเฟรมเดียวอาจทําให้เทรดหลัก ไม่ตอบสนองภายในระยะเวลาของเฟรม เช่น
- กำลังแสดงผลรายการนอกหน้าจอที่ไม่จำเป็นหลายรายการ
- ใช้อัลกอริทึมที่ไม่มีประสิทธิภาพ เช่น
O(n^2)
เมื่อแสดงผล UI หลายรายการ จากองค์ประกอบเหล่านี้
ถูกบล็อกโดยคอมโพเนนต์อื่น
หากคอมโพเนนต์อื่น เช่น Broadcast Receiver บล็อกเทรดหลักสำหรับ นานกว่า 5 วินาที อาจทำให้เกิด ANR ของการจ่ายงานอินพุตและข้อขัดข้องร้ายแรง
หลีกเลี่ยงการทํางานหนักๆ ในเทรดหลักในคอมโพเนนต์ของแอป เรียกใช้การออกอากาศ ตัวรับในชุดข้อความอื่นเมื่อเป็นไปได้