เมื่อเทรด UI ของแอป Android ถูกบล็อกนานเกินไป "แอปพลิเคชัน ไม่ตอบสนอง" ข้อผิดพลาด (ANR) แสดงขึ้น หากแอปอยู่เบื้องหน้า การตั้งค่า ระบบจะแสดงกล่องโต้ตอบแก่ผู้ใช้ ดังที่แสดงในรูปที่ 1 กล่องโต้ตอบ ANR ให้ โอกาสให้ผู้ใช้บังคับปิดแอปได้
ANR มีปัญหาเนื่องจากเทรดหลักของแอป ซึ่งเป็นต้นเหตุ อัปเดต UI ไม่สามารถประมวลผลเหตุการณ์การป้อนข้อมูลของผู้ใช้หรือการสร้างรูปภาพ ทําให้ผู้ใช้ไม่พอใจ ผู้ใช้รายนั้น ดูข้อมูลเพิ่มเติมเกี่ยวกับเทรดหลักของแอปได้ที่กระบวนการและ ชุดข้อความ
ANR จะทริกเกอร์แอปของคุณเมื่อเงื่อนไขข้อใดข้อหนึ่งต่อไปนี้เกิดขึ้น
- หมดเวลาการส่งอินพุต: หากแอปไม่ตอบสนองต่ออินพุต เหตุการณ์ (เช่น การกดแป้นหรือหน้าจอสัมผัส) ภายใน 5 วินาที
- การเรียกใช้บริการ: หากบริการที่แอปของคุณประกาศไว้ดำเนินการไม่เสร็จสิ้น
กำลังเรียกใช้
Service.onCreate()
และService.onStartCommand()
/Service.onBind()
ภายในไม่กี่วินาที - ไม่ได้เรียก Service.startForeground(): หากแอปใช้
Context.startForegroundService()
เพื่อเริ่มบริการใหม่ในเบื้องหน้า แต่บริการจะไม่เรียกใช้startForeground()
ภายใน 5 วินาที - ประกาศความตั้งใจ: หาก
BroadcastReceiver
ดำเนินการไม่เสร็จสิ้นภายในระยะเวลาที่กำหนด หากแอปมี ในเบื้องหน้า ระยะหมดเวลานี้คือ 5 วินาที - การโต้ตอบกับ JobScheduler: หาก
JobService
ไม่แสดงผล จากJobService.onStartJob()
หรือJobService.onStopJob()
ภายในไม่กี่เดือน วินาที หรือหากงานที่เริ่มต้นโดยผู้ใช้ เริ่มต้น และแอปของคุณไม่เรียกใช้JobService.setNotification()
ภายในไม่กี่ วินาทีหลังจากที่มีการเรียกJobService.onStartJob()
สำหรับการกำหนดเป้าหมายแอป Android 13 และต่ำกว่า จะไม่มีการแจ้งเตือน ANR และไม่มีการรายงานไปยังแอป สำหรับแอปที่กำหนดเป้าหมายเป็น Android 14 ขึ้นไป ANR ระบุไว้ชัดเจนและ รายงานไปที่แอป
หากแอปพบ ANR คุณสามารถใช้คำแนะนำในบทความนี้เพื่อ วินิจฉัยและแก้ไขปัญหา
ตรวจหาปัญหา
หากเผยแพร่แอปแล้ว คุณสามารถใช้ Android Vitals เพื่อดูข้อมูลเกี่ยวกับ ANR สำหรับแอปของคุณ คุณใช้ เครื่องมือในการตรวจจับ ANR ภาคสนามแต่โปรดทราบว่าเครื่องมือของบุคคลที่สามไม่สามารถรายงาน ANR ใน Android เวอร์ชันเก่า (Android 10 และต่ำกว่า) ซึ่งต่างจาก Android Vitals
Android Vitals
Android Vitals ช่วยคุณตรวจสอบและปรับปรุงอัตรา ANR ของแอปได้ Android Vitals วัดอัตรา ANR หลายอัตราดังนี้
- อัตรา ANR: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวันที่ พบ ANR ทุกประเภท
- อัตรา ANR ที่ผู้ใช้รับรู้: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวัน
ที่พบ ANR ที่ผู้ใช้รับรู้อย่างน้อย 1 ครั้ง ขณะนี้เฉพาะ ANR ของ
ประเภท
Input dispatching timed out
จะถือว่าผู้ใช้รับรู้ - อัตรา ANR หลายรายการ: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวันซึ่ง พบ ANR อย่างน้อย 2 ครั้ง
ผู้ใช้ที่ใช้งานอยู่รายวันคือผู้ใช้ที่ไม่ซ้ำที่ใช้แอปของคุณ ในวันเดียวบนอุปกรณ์เดียว ซึ่งอาจมีมากกว่าหลายเซสชัน หากผู้ใช้ใช้แอปของคุณบนอุปกรณ์มากกว่า 1 เครื่องใน 1 วัน อุปกรณ์แต่ละเครื่องจะรวม กับจำนวนผู้ใช้ที่ใช้งานอยู่ในวันนั้น หากมีผู้ใช้หลายคนใช้อุปกรณ์เดียวกันในวันเดียวกัน ก็จะนับเป็นผู้ใช้ที่ใช้งานอยู่ 1 คน
อัตรา ANR ที่ผู้ใช้รับรู้เป็น Vitals หลักซึ่งส่งผลต่อ การค้นพบได้ของแอปคุณใน Google Play มีความสำคัญเพราะ ANR มักเกิดขึ้นเมื่อผู้ใช้มีส่วนร่วมกับแอป ซึ่งทำให้เกิด ขัดข้อง
Play ได้กำหนดเกณฑ์ลักษณะการทำงานที่ไม่ถูกต้อง 2 เกณฑ์ในเมตริกนี้ไว้ดังนี้
- เกณฑ์ลักษณะการทำงานที่ไม่ถูกต้องโดยรวม: อย่างน้อย 0.47% ของผู้ใช้ที่ใช้งานอยู่รายวัน พบ ANR ที่ผู้ใช้รับรู้ในอุปกรณ์ทุกรุ่น
- เกณฑ์ลักษณะการทำงานที่ไม่ถูกต้องในแต่ละอุปกรณ์: อย่างน้อย 8% ของผู้ใช้รายวัน พบ ANR ที่ผู้ใช้รับรู้สำหรับอุปกรณ์รุ่นเดียว
หากแอปเกินเกณฑ์ลักษณะการทํางานที่ไม่ถูกต้องโดยรวม อาจเป็นไปได้ว่า ค้นพบได้น้อยลงในทุกอุปกรณ์ หากแอปเกินขีดจำกัดที่ส่งผลเสียต่ออุปกรณ์ เกณฑ์ลักษณะการทำงานในอุปกรณ์บางประเภท ซึ่งมีแนวโน้มที่จะค้นพบได้น้อยลงใน อุปกรณ์เหล่านั้น และอาจแสดงคำเตือนในข้อมูลผลิตภัณฑ์ใน Store ของคุณ
Android Vitals สามารถแจ้งเตือนคุณผ่าน Play Console เมื่อแอปแสดง ANR มากเกินไป
สำหรับข้อมูลเกี่ยวกับวิธีที่ Google Play รวบรวมข้อมูล Android Vitals โปรดดู Play Console เอกสารประกอบ
วินิจฉัย ANR
รูปแบบทั่วไปที่ควรพิจารณาเมื่อวินิจฉัย ANR มีดังนี้
- แอปดำเนินการช้าที่เกี่ยวข้องกับ I/O ในเทรดหลัก
- แอปทำการคำนวณที่ยาวนานในเทรดหลัก
- เทรดหลักจะทำการเรียก Binder แบบซิงโครนัสไปยังกระบวนการอื่น และ กระบวนการอื่นใช้เวลานานในการส่งคืน
- เทรดหลักถูกบล็อกขณะรอบล็อกที่ซิงค์เป็นเวลานาน ที่เกิดขึ้นในชุดข้อความอื่น
- เทรดหลักอยู่ในระยะติดตายโดยมีเทรดอื่นอยู่ในเทรด หรือผ่านทาง Binder เทรดหลักไม่ต้องรอนาน ดำเนินการให้เสร็จสิ้น แต่อยู่ในสถานการณ์ติดตาย สำหรับข้อมูลเพิ่มเติม ดู Deadlock บน Wikipedia
เทคนิคต่อไปนี้จะช่วยคุณระบุสาเหตุของ ANR ได้
สถิติสุขภาพ
HealthStats
มีเมตริกเกี่ยวกับ
ประสิทธิภาพของแอปพลิเคชันโดยการบันทึกเวลาทั้งหมดของผู้ใช้ เวลาระบบ เวลา CPU
เครือข่าย สถิติวิทยุ เวลาเปิด/ปิดหน้าจอ และการปลุก วิธีนี้
ความช่วยเหลือในการวัดการใช้งาน CPU โดยรวมและการระบายแบตเตอรี่
แก้ไขข้อบกพร่อง
Debug
ช่วยตรวจสอบแอปพลิเคชัน Android
ระหว่างการพัฒนา รวมทั้งการติดตามและการจัดสรรที่จะนับเพื่อระบุการกระตุก
และความล่าช้าในการใช้แอป คุณยังใช้ Debug
เพื่อรับรันไทม์และหน่วยความจำในเครื่องได้ด้วย
ตัวนับและเมตริกหน่วยความจำที่ช่วยระบุร่องรอยหน่วยความจำได้
ของกระบวนการหนึ่งๆ โดยเฉพาะ
ข้อมูลการออกของแอปพลิเคชัน
ApplicationExitInfo
ใช้ได้
ใน Android 11 (API ระดับ 30) ขึ้นไป และให้ข้อมูลเกี่ยวกับ
เหตุผลที่ผู้ใช้ออกจากแอปพลิเคชัน ซึ่งได้แก่ ANR, หน่วยความจำต่ำ, ข้อขัดข้องของแอป
การใช้งาน CPU มากเกินไป การหยุดชะงักของผู้ใช้ การหยุดชะงักของระบบ หรือรันไทม์
การเปลี่ยนแปลงสิทธิ์
โหมดจำกัด
การใช้ StrictMode
จะช่วยให้คุณค้นพบ
การดําเนินการ I/O โดยไม่ตั้งใจในเทรดหลักขณะที่คุณพัฒนาแอป
คุณสามารถใช้ StrictMode
ที่ระดับแอปพลิเคชันหรือกิจกรรม
เปิดใช้กล่องโต้ตอบ ANR เบื้องหลัง
Android แสดงกล่องโต้ตอบ ANR สำหรับแอปที่ใช้เวลาประมวลผลการออกอากาศนานเกินไป ข้อความเฉพาะเมื่อแสดง ANR ทั้งหมดในนักพัฒนาแอปของอุปกรณ์ ตัวเลือกเพิ่มเติม ด้วยเหตุนี้ กล่องโต้ตอบ ANR เบื้องหลังจึงไม่แสดงกับ ผู้ใช้ แต่แอปอาจยังมีปัญหาด้านประสิทธิภาพอยู่
Traceview
คุณสามารถใช้ Traceview เพื่อดูการติดตามการทำงานของแอปที่ทำงานอยู่ Use Case และระบุตำแหน่งที่เทรดหลักไม่ว่าง สำหรับข้อมูล เกี่ยวกับวิธีใช้ Traceview โปรดดูการทำโปรไฟล์ด้วย Traceview และ dmtracedump
ดึงไฟล์การติดตาม
Android จัดเก็บข้อมูลการติดตามเมื่อพบ ANR ในระบบปฏิบัติการเวอร์ชันเก่า
จะมีไฟล์ /data/anr/traces.txt
ไฟล์เดียวในอุปกรณ์
ในระบบปฏิบัติการรุ่นใหม่ๆ จะมีไฟล์ /data/anr/anr_*
หลายไฟล์
คุณสามารถเข้าถึงการติดตาม ANR จากอุปกรณ์หรือโปรแกรมจำลองได้โดยใช้
Android Debug Bridge (adb) เป็นรูท:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
คุณบันทึกรายงานข้อบกพร่องจากอุปกรณ์จริงได้โดยใช้ฟีเจอร์ "รับข้อบกพร่อง" รายงานตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์บนอุปกรณ์ หรือคำสั่ง adbbugreport บนอุปกรณ์ เครื่องสำหรับพัฒนาซอฟต์แวร์ ดูข้อมูลเพิ่มเติมได้ที่การบันทึกและอ่านข้อบกพร่อง รายงานของ Google
แก้ไขปัญหา
หลังจากที่คุณระบุปัญหาได้แล้ว คุณสามารถใช้เคล็ดลับในส่วนนี้เพื่อ แก้ไขปัญหาที่พบได้ทั่วไป
โค้ดที่ช้าในเทรดหลัก
ระบุตำแหน่งในโค้ดที่เทรดหลักของแอปไม่ว่างเพื่อดูข้อมูลเพิ่มเติม 5 วินาที มองหากรณีการใช้งานที่น่าสงสัยในแอปแล้วลอง ทำ ANR ซ้ำ
ตัวอย่างเช่น รูปที่ 2 แสดงไทม์ไลน์ Traceview ที่เทรดหลักไม่ว่าง นานกว่า 5 วินาที
รูปที่ 2 แสดงให้เห็นว่าโค้ดที่ไม่เหมาะสมส่วนใหญ่เกิดขึ้นใน
onClick(View)
ดังแสดงในตัวอย่างโค้ดต่อไปนี้
Kotlin
override fun onClick(v: View) { // This task runs on the main thread. BubbleSort.sort(data) }
Java
@Override public void onClick(View view) { // This task runs on the main thread. BubbleSort.sort(data); }
ในกรณีนี้ คุณควรย้ายงานที่ทำงานในเทรดหลักไปยังผู้ปฏิบัติงาน ชุดข้อความ เฟรมเวิร์ก Android มีคลาสที่ช่วยย้ายงานได้ ไปยังชุดข้อความของผู้ปฏิบัติงาน ดูผู้ปฏิบัติงาน ชุดข้อความเพิ่มเติม
IO ในชุดข้อความหลัก
การดำเนินการ IO ในเทรดหลักเป็นสาเหตุที่พบบ่อยที่ทำให้การดำเนินการล่าช้า ในเทรดหลัก ซึ่งอาจทำให้เกิด ANR เราขอแนะนำให้ย้าย IO ทั้งหมด การดำเนินการกับชุดข้อความของผู้ปฏิบัติงานตามที่แสดงในส่วนก่อนหน้า
ตัวอย่างบางส่วนของการดำเนินการ IO คือการดำเนินการเครือข่ายและพื้นที่เก็บข้อมูล สำหรับข้อมูลเพิ่มเติม โปรดดูที่เครือข่ายที่มีประสิทธิภาพ การดำเนินการ และการบันทึก ข้อมูล
การช่วงชิงล็อก
ในบางกรณี งานที่ทำให้เกิด ANR จะไม่ดำเนินการโดยตรงใน เทรดหลักของแอป หากเทรดผู้ปฏิบัติงานมีการล็อกในทรัพยากรที่หลัก เทรดต้องทำงานให้เสร็จสมบูรณ์ก่อน อาจทำให้เกิด ANR
ตัวอย่างเช่น รูปที่ 3 แสดงไทม์ไลน์ Traceview ซึ่งงานส่วนใหญ่ ดำเนินการกับชุดข้อความของผู้ปฏิบัติงาน
รูปที่ 3 ไทม์ไลน์มุมมองการติดตามที่แสดงงานที่กำลังดำเนินการกับผู้ปฏิบัติงาน ชุดข้อความ
แต่หากผู้ใช้ยังพบ ANR คุณควรดูที่สถานะของ
เทรดหลักในการตรวจสอบอุปกรณ์ Android โดยปกติแล้ว เทรดหลักจะอยู่ใน
RUNNABLE
ว่าพร้อมอัปเดต UI หรือไม่ และมักปรับเปลี่ยนตามอุปกรณ์
แต่หากเทรดหลักดำเนินการต่อไม่ได้ แสดงว่าเทรดหลักจะอยู่ใน
สถานะ BLOCKED
และตอบสนองต่อกิจกรรมไม่ได้ สถานะจะแสดงในการตรวจสอบอุปกรณ์ Android เป็น
ตรวจสอบหรือรอ ดังที่แสดงในรูปที่ 5
การติดตามต่อไปนี้แสดงเทรดหลักของแอปที่ถูกบล็อกขณะรอ แหล่งข้อมูล:
...
AsyncTask #2" prio=5 tid=18 Runnable
| group="main" sCount=0 dsCount=0 obj=0x12c333a0 self=0x94c87100
| sysTid=25287 nice=10 cgrp=default sched=0/0 handle=0x94b80920
| state=R schedstat=( 0 0 0 ) utm=757 stm=0 core=3 HZ=100
| stack=0x94a7e000-0x94a80000 stackSize=1038KB
| held mutexes= "mutator lock"(shared held)
at com.android.developer.anrsample.BubbleSort.sort(BubbleSort.java:8)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:147)
- locked <0x083105ee> (a java.lang.Boolean)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:135)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
...
การตรวจสอบการติดตามจะช่วยให้คุณหาโค้ดที่บล็อกเทรดหลักได้ รหัสต่อไปนี้มีหน้าที่ในการระงับล็อกที่บล็อกรหัสหลัก เทรดในการติดตามก่อนหน้า:
Kotlin
override fun onClick(v: View) { // The worker thread holds a lock on lockedResource LockTask().execute(data) synchronized(lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } class LockTask : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? = synchronized(lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]) } }
Java
@Override public void onClick(View v) { // The worker thread holds a lock on lockedResource new LockTask().execute(data); synchronized (lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } public class LockTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]); } } }
อีกตัวอย่างหนึ่งคือเทรดหลักของแอปที่รอผลลัพธ์จาก
เทรดผู้ปฏิบัติงาน ตามที่แสดงในโค้ดต่อไปนี้ โปรดทราบว่าการใช้ wait()
และ
notify()
ไม่ใช่รูปแบบที่แนะนำใน Kotlin ซึ่งมีกลไกของตัวเอง
ในการจัดการการเกิดขึ้นพร้อมกัน เมื่อใช้ Kotlin คุณควรใช้ Kotlin โดยเฉพาะ
หากเป็นไปได้
Kotlin
fun onClick(v: View) { val lock = java.lang.Object() val waitTask = WaitTask(lock) synchronized(lock) { try { waitTask.execute(data) // Wait for this worker thread’s notification lock.wait() } catch (e: InterruptedException) { } } } internal class WaitTask(private val lock: java.lang.Object) : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { synchronized(lock) { BubbleSort.sort(params[0]) // Finished, notify the main thread lock.notify() } } }
Java
public void onClick(View v) { WaitTask waitTask = new WaitTask(); synchronized (waitTask) { try { waitTask.execute(data); // Wait for this worker thread’s notification waitTask.wait(); } catch (InterruptedException e) {} } } class WaitTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (this) { BubbleSort.sort(params[0]); // Finished, notify the main thread notify(); } } }
มีสถานการณ์อื่นๆ ที่บล็อกเทรดหลักได้ ซึ่งรวมถึง
ชุดข้อความที่ใช้ Lock
Semaphore
,
และระดับทรัพยากร (เช่น แหล่งรวมการเชื่อมต่อฐานข้อมูล)
หรือกลไกการยกเว้นร่วมกัน (หลายฝ่าย) อื่นๆ
คุณควรประเมินล็อกที่แอปใช้ทรัพยากรโดยทั่วไป แต่ หากต้องการหลีกเลี่ยง ANR คุณควรดูที่ล็อกที่ค้างไว้เพื่อหาทรัพยากร ที่จำเป็นสำหรับเทรดหลัก
ตรวจสอบว่าล็อกล็อกไว้เป็นเวลาน้อยที่สุด หรือยิ่งไปกว่านั้น
ประเมินดูว่าแอปจำเป็นต้องมีการระงับไว้ตั้งแต่ต้นหรือไม่ หากคุณกำลังใช้
ล็อกเพื่อระบุว่าจะอัปเดต UI เมื่อใด โดยอิงตามการประมวลผลของเธรดผู้ปฏิบัติงาน
ใช้กลไกอย่าง
onProgressUpdate()
และ
onPostExecute()
เพื่อสื่อสารระหว่างผู้ปฏิบัติงานและเทรดหลัก
เดดล็อก
การติดตายจะเกิดขึ้นเมื่อเทรดเข้าสู่สถานะรอเนื่องจากจำเป็นต้องมี ทรัพยากรถูกระงับโดยชุดข้อความอื่น ซึ่งกำลังรอทรัพยากรที่ ถือโดย ชุดข้อความแรก หากเทรดหลักของแอปอยู่ในสถานการณ์นี้ ANR ให้เกิดขึ้น
การตายเป็นปรากฏการณ์ที่มีการศึกษากันเป็นอย่างดีในแวดวงวิทยาการคอมพิวเตอร์ อัลกอริทึมการป้องกันการติดตายที่คุณสามารถใช้เพื่อหลีกเลี่ยงการติดตาย
ดูข้อมูลเพิ่มเติมได้ที่การหยุดทำงานและ การป้องกันการหยุดทำงาน อัลกอริทึมเปิดอยู่ Wikipedia
Broadcast Receiver ที่ช้า
แอปสามารถตอบสนองต่อข้อความที่เผยแพร่ เช่น เปิดหรือปิดใช้เครื่องบิน หรือการเปลี่ยนแปลงสถานะการเชื่อมต่อ โดยใช้ Broadcast Receiver ANR เกิดขึ้นเมื่อแอปใช้เวลานานเกินไปในการประมวลผลข้อความประกาศ
ANR เกิดขึ้นในกรณีต่อไปนี้
- Broadcast Receiver ยังดำเนินการไม่เสร็จสิ้น
onReceive()
ภายในระยะเวลาที่กำหนด - สายเรียกเข้าจาก Broadcast Receiver
goAsync()
เรียกใช้ไม่ได้finish()
ในPendingResult
ออบเจ็กต์
แอปของคุณควรดำเนินการสั้นๆ เฉพาะใน
onReceive()
วิธีการ
BroadcastReceiver
แต่หากแอปของคุณต้องใช้สิทธิ์ที่ซับซ้อนมากขึ้น
เป็นผลของข้อความประกาศ คุณควรเลื่อนงานออกไปให้
IntentService
คุณสามารถใช้เครื่องมือ เช่น Traceview เพื่อระบุได้ว่า Broadcast Receiver ประมวลผลหรือไม่ การดำเนินการที่ใช้เวลานานในเทรดหลักของแอป เช่น รูปที่ 6 แสดง ไทม์ไลน์ของ Broadcast Receiver ที่ประมวลผลข้อความในชุดข้อความหลัก เป็นเวลาประมาณ 100 วินาที
การทำงานลักษณะนี้อาจเกิดจากการดำเนินการที่ใช้เวลานานใน
onReceive()
ของวิธีการ
BroadcastReceiver
,
ดังที่ปรากฏในตัวอย่างต่อไปนี้
Kotlin
override fun onReceive(context: Context, intent: Intent) { // This is a long-running operation BubbleSort.sort(data) }
Java
@Override public void onReceive(Context context, Intent intent) { // This is a long-running operation BubbleSort.sort(data); }
ในสถานการณ์เช่นนี้ ขอแนะนำให้ย้ายการดำเนินการที่ใช้เวลานานไปยัง
IntentService
เนื่องจากใช้
เทรดผู้ปฏิบัติงานเพื่อดำเนินการ โค้ดต่อไปนี้แสดงวิธีใช้
IntentService
เพื่อประมวลผล
การดำเนินการที่ใช้เวลานาน:
Kotlin
override fun onReceive(context: Context, intent: Intent) { Intent(context, MyIntentService::class.java).also { intentService -> // The task now runs on a worker thread. context.startService(intentService) } } class MyIntentService : IntentService("MyIntentService") { override fun onHandleIntent(intent: Intent?) { BubbleSort.sort(data) } }
Java
@Override public void onReceive(Context context, Intent intent) { // The task now runs on a worker thread. Intent intentService = new Intent(context, MyIntentService.class); context.startService(intentService); } public class MyIntentService extends IntentService { @Override protected void onHandleIntent(@Nullable Intent intent) { BubbleSort.sort(data); } }
จากการใช้
IntentService
การทดสอบระยะยาว
ระบบจะดำเนินการในเทรดของผู้ปฏิบัติงานแทนเทรดหลัก ภาพที่ 7
แสดงงานที่เลื่อนไปยังเทรดผู้ปฏิบัติงานในไทม์ไลน์ Traceview
Broadcast Receiver สามารถใช้
goAsync()
เพื่อส่งสัญญาณแจ้งว่าต้องการเวลาเพิ่มเติมในการประมวลผลข้อความ อย่างไรก็ตาม
เธอควรโทรหา
finish()
ใน
PendingResult
ออบเจ็กต์ ตัวอย่างต่อไปนี้จะแสดงวิธีการเรียกFinish() เพื่อให้ระบบ
นำ Broadcast Receiver มารีไซเคิลและหลีกเลี่ยง ANR
Kotlin
val pendingResult = goAsync() object : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { // This is a long-running operation BubbleSort.sort(params[0]) pendingResult.finish() return 0L } }.execute(data)
Java
final PendingResult pendingResult = goAsync(); new AsyncTask<Integer[], Integer, Long>() { @Override protected Long doInBackground(Integer[]... params) { // This is a long-running operation BubbleSort.sort(params[0]); pendingResult.finish(); } }.execute(data);
อย่างไรก็ตาม การย้ายโค้ดจาก Broadcast Receiver แบบช้าไปยังเทรดอื่นและ
กำลังใช้ goAsync()
จะไม่แก้ไข ANR หากการออกอากาศอยู่ในเบื้องหลัง
ระยะหมดเวลา ANR ยังคงมีผล
กิจกรรมเกม
ไลบรารี GameActivity
ได้ลด ANR ใน
กรณีศึกษาของเกมและแอปที่เขียน
ใน C หรือ C++ หากคุณแทนที่กิจกรรมโฆษณาเนทีฟที่มีอยู่ด้วย GameActivity
คุณจะลดการบล็อกชุดข้อความ UI และป้องกันไม่ให้เกิด ANR บางอย่างได้
โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับ ANR ที่ ทำให้แอปปรับเปลี่ยนตามอุปกรณ์อยู่เสมอ สำหรับข้อมูลเพิ่มเติม ข้อมูลเกี่ยวกับชุดข้อความ โปรดดู ประสิทธิภาพของชุดข้อความ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การปลุกระบบบ่อยเกินไป