ANR ในการพัฒนา Android — คืออะไร สาเหตุ และวิธีการแก้ไข

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-28 เวลาอ่าน: 9 นาที

ANR (Application Not Responding) คือการแจ้งเตือนระบบ Android ที่ปรากฏขึ้นเมื่อแอปหยุดตอบสนองต่ออินพุตของผู้ใช้เป็นเวลานานกว่า 5 วินาที ตามข้อมูลจาก Android Developers สาเหตุหลักคือการดำเนินการที่ยาวนานบนเธรดหลักซึ่งขัดขวางการประมวลผลการสัมผัสและการเรนเดอร์อินเทอร์เฟซ การทำความเข้าใจ กลไก ANR เป็นสิ่งจำเป็นสำหรับนักพัฒนา Android ทุกคนในการสร้างแอปพลิเคชันที่ตอบสนองได้ดี

ประเด็นสำคัญ

  • ANR — คำเตือนระบบ Android เมื่อแอปค้างนานกว่า 5 วินาที
  • เธรดหลัก (เธรด UI) — ที่เดียวที่การบล็อกนำไปสู่ ANR
  • InputDispatcher — คอมโพเนนต์ระบบที่ตรวจจับความล่าช้าของอินพุตและเรียกใช้ ANR
  • traces.txt — ไฟล์สำคัญสำหรับวินิจฉัยสาเหตุของการค้างบนอุปกรณ์
  • StrictMode — เครื่องมือในตัวของ Android สำหรับตรวจจับการดำเนินการที่ยาวนานบนเธรด UI

ANR คืออะไร

ANR (Application Not Responding) คือกล่องโต้ตอบของระบบปฏิบัติการ Android ที่ปรากฏขึ้นเมื่อแอปหยุดตอบสนองต่ออินพุตของผู้ใช้ ระบบจะติดตามเวลาการประมวลผลเหตุการณ์ผ่าน InputDispatcher: หากการสัมผัสหรือการกดปุ่มไม่ได้รับการจัดการภายใน 5 วินาที Android จะแสดงกล่องโต้ตอบที่เสนอให้ปิดหรือรอแอป

กลไก ANR ปกป้อง ประสบการณ์ผู้ใช้ จากแอปที่ค้าง Android ไม่อนุญาตให้แอปหนึ่งบล็อกทั้งระบบ — ไม่เหมือนระบบปฏิบัติการเดสก์ท็อป แพลตฟอร์มมือถือจะจำกัดเวลาการประมวลผลเหตุการณ์โดยบังคับ BroadcastReceiver มีขีดจำกัด 10 วินาที และบริการเบื้องหน้ามี 20 วินาที

ANR ไม่ใช่ข้อยกเว้นในโค้ด — มันคือ กลไกระบบ ในระดับกระบวนการ Linux Android ส่งสัญญาณ SIGQUIT ไปยังกระบวนการ จากนั้นระบบจะบันทึกสแต็กการเรียกของเธรดทั้งหมดลงในไฟล์ traces.txt นักพัฒนาไม่ได้รับ ANR เป็นข้อยกเว้น catch แต่เป็นรายงานหลังจากรีสตาร์ทแอป บน Android 11+ API ApplicationExitInfo อนุญาตให้รับสาเหตุของการสิ้นสุดกระบวนการโดยทางโปรแกรม รวมถึง ANR — ซึ่งช่วยลดความซับซ้อนในการรวบรวมสถิติโดยไม่ต้องวิเคราะห์ traces.txt ด้วยตนเอง

สาเหตุหลักของ ANR

ห้าหมวดหมู่ ของการดำเนินการนำไปสู่ ANR ในแอป Android อย่างสม่ำเสมอ แต่ละหมวดหมู่จะบล็อกเธรดหลัก ป้องกันไม่ให้ระบบประมวลผลเหตุการณ์อินพุตและการวาดหน้าจอใหม่

คำขอเครือข่ายบนเธรดหลัก

คำขอ HTTP แบบซิงโครนัส ที่ดำเนินการบนเธรด UI เป็นสาเหตุที่พบบ่อยที่สุดของ ANR ในหมู่นักพัฒนามือใหม่ แม้แต่คำขอที่รวดเร็วไปยังเซิร์ฟเวอร์ก็อาจใช้เวลา 1–3 วินาที และหากการเชื่อมต่อไม่ดี — 30 วินาทีหรือมากกว่า Android ห้ามการดำเนินการเครือข่ายบนเธรดหลักอย่างชัดเจนตั้งแต่ API 11 โดยโยน NetworkOnMainThreadException

ใช้ Coroutines หรือ RxJava สำหรับการเรียกแบบอะซิงโครนัส Coroutine กับตัวจัดส่ง Dispatchers.IO จะดำเนินการคำขอบนเธรดพื้นหลังและส่งผลลัพธ์ไปยังเธรดหลักผ่าน Dispatchers.Main ซึ่งช่วยขจัดการบล็อกเธรด UI โดยการดำเนินการเครือข่ายได้อย่างสมบูรณ์

kotlin
fun fetchUserData() {
    CoroutineScope(Dispatchers.Main).launch {
        val result = withContext(Dispatchers.IO) {
            api.getUserData() // การดำเนินการพื้นหลัง
        }
        updateUI(result) // ผลลัพธ์บนเธรดหลัก
    }
}

การคำนวณที่เข้มข้นบนเธรด UI

การประมวลผล อาร์เรย์ข้อมูลขนาดใหญ่ การแยกวิเคราะห์ JSON หรือ XML การทำงานกับบิตแมปโดยตรงบนเธรดหลัก — สาเหตุที่พบบ่อยเป็นอันดับสองของ ANR แม้แต่ 300 มิลลิวินาทีของการทำงานต่อเนื่องของเธรด UI โดยไม่กลับไปยังลูปเหตุการณ์ก็ทำให้เกิดความล่าช้าในการเรนเดอร์อย่างเห็นได้ชัด และขีดจำกัด 5 วินาทีจะถูกบันทึกเป็น ANR

WorkManager และบริการพื้นหลังถูกออกแบบมาเพื่อย้ายการคำนวณหนักออกจากเธรดหลัก ใช้ AsyncTask (เลิกใช้แล้ว), ListenableFuture หรือ Kotlin Flow เพื่อส่งข้อมูลเป็นชิ้นส่วนโดยไม่บล็อก UI

ล็อกการซิงโครไนซ์และ Deadlock

Deadlock เกิดขึ้นเมื่อสองเธรดถือล็อกและรอซึ่งกันและกัน หากหนึ่งในเธรดเป็นเธรดหลัก ระบบจะบันทึก ANR หลังจาก 5 วินาทีพอดี Thread.join(), CountDownLatch.await() และบล็อก synchronized ที่เรียกจากเธรด UI มีความเสี่ยงในการบล็อก

หลีกเลี่ยง การดำเนินการที่บล็อก ใดๆ บนเธรดหลัก แทนที่จะใช้ synchronized ให้ใช้ ConcurrentHashMap; แทน Thread.join() — coroutine กับ async/await กฎนี้ใช้กับทุกภาษาใน Android: Java, Kotlin หรือ C++ ผ่าน JNI

BroadcastReceiver ที่ทำงานยาวนาน

BroadcastReceiver ทำงานบนเธรดหลักโดยค่าเริ่มต้น หาก onReceive() ยุ่งนานกว่า 10 วินาที Android จะแสดง ANR การโหลดข้อมูลจากฐานข้อมูลหรือเครือข่ายภายใน onReceive เป็นเส้นทางที่แน่นอนไปสู่การค้าง

ใช้ goAsync() ภายใน BroadcastReceiver เพื่อสลับไปยังเธรดพื้นหลัง หรือ registerReceiver กับ getBackgroundBroadcastReceiver() ซึ่งช่วยให้ประมวลผลเหตุการณ์โดยไม่บล็อก UI

ContentProvider และ SQLite บนเธรดหลัก

คำสั่ง หนัก ไปยัง ContentProvider หรือการทำงานโดยตรงกับ SQLite บนเธรด UI — สาเหตุที่เห็นได้ชัดน้อยกว่าแต่พบบ่อยของ ANR ระหว่างการย้ายฐานข้อมูลหรือการแทรกบันทึกจำนวนมากเป็นพันรายการ เวลาดำเนินการอาจเกินขีดจำกัด 5 วินาที

ย้ายการดำเนินการ ฐานข้อมูล ทั้งหมดไปยังเธรดพื้นหลังโดยใช้ Room กับฟังก์ชัน suspend Room จะตรวจสอบโดยอัตโนมัติว่าคำสั่งไม่ได้ดำเนินการบนเธรดหลักและโยนข้อยกเว้นหากละเมิด

วิธีวินิจฉัย ANR

การวินิจฉัย ANR แตกต่างจากการดีบักข้อยกเว้นปกติ — คุณไม่สามารถจับ ANR ในบล็อก try-catch แหล่งข้อมูลหลักคือไฟล์ traces.txt ซึ่ง Android สร้างขึ้นในขณะที่ค้าง

traces.txt ประกอบด้วยสแต็กการเรียกของเธรดแอปทั้งหมดในขณะที่เกิด ANR หากต้องการอ่านไฟล์จากอุปกรณ์จริง ให้รันคำสั่ง adb bugreport ซึ่งรวบรวมรายงานระบบที่สมบูรณ์รวมถึง ANR ทั้งหมดล่าสุด สำหรับอีมูเลเตอร์ ไฟล์สามารถเข้าถึงได้ที่ /data/anr/traces.txt สแต็กการเรียกแสดงให้เห็นว่าเมธอดใดกำลังดำเนินการบนเธรดหลักในขณะที่เกิดการบล็อก

text
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt

Google Play Console มีส่วน ANR & Crash พร้อมรายงานรวมและความถี่ข้อผิดพลาด สำหรับแต่ละ ANR จะแสดงสแต็กการเรียกและสถิติอุปกรณ์: รุ่น, เวอร์ชัน Android, ภูมิภาค ซึ่งช่วยระบุ ANR ที่ขึ้นอยู่กับอุปกรณ์หรือเวอร์ชันระบบเฉพาะ

Android Studio ตั้งแต่ปี 2021 มี ANR Watchdog ในโปรไฟเลอร์ มันจะบันทึกดัมพ์เธรดโดยอัตโนมัติหากเธรดหลักไม่ตอบสนองนานกว่าเวลาที่กำหนด เครื่องมือจะแสดงไทม์ไลน์ของเหตุการณ์: การดำเนินการใดเริ่มต้นขึ้น เมธอดใดถูกดำเนินการ และการบล็อกเกิดขึ้นที่ขั้นตอนใด

วิธีป้องกัน ANR

การป้องกัน ANR สร้างขึ้นบนกฎพื้นฐานข้อเดียว: เธรดหลักควรจัดการเฉพาะเหตุการณ์ UI เท่านั้น การดำเนินการใดๆ ที่ยาวนานกว่า 16 มิลลิวินาที (เวลาหนึ่งเฟรม) ควรดำเนินการบนเธรดพื้นหลัง

StrictMode — การตรวจสอบอัตโนมัติ

StrictMode เป็นเครื่องมือในตัวของ Android สำหรับตรวจจับ ANR ที่อาจเกิดขึ้นระหว่างการพัฒนา เปิดใช้งานใน Application.onCreate() ด้วยแฟล็กสำหรับการดำเนินการดิสก์และเครือข่าย เมื่อละเมิด StrictMode จะโยนข้อยกเว้นหรือเขียนไปยัง logcat

kotlin
if (BuildConfig.DEBUG) {
    StrictMode.ThreadPolicy.Builder()
        .detectDiskReads()
        .detectDiskWrites()
        .detectNetwork()
        .penaltyLog()
        .build()
        .let { StrictMode.setThreadPolicy(it) }
}

รูปแบบอะซิงโครนัส: Coroutines และ RxJava

Kotlin Coroutines — วิธีมาตรฐานสำหรับการทำงานแบบอะซิงโครนัสในแอป Android สมัยใหม่ แนวทางหลัก: การดำเนินการ I/O ทำงานบน Dispatchers.IO ผลลัพธ์จะถูกส่งไปยัง Dispatchers.Main สำหรับการอัปเดต UI สำหรับสถานการณ์แบบ Flow ให้ใช้ Dispatchers.Default สำหรับงานที่ใช้ CPU มาก

RxJava ยังคงได้รับความนิยมในโปรเจกต์เก่า subscribeOn(Schedulers.io()) และ observeOn(AndroidSchedulers.mainThread()) — ชุดขั้นต่ำสำหรับการป้องกัน ANR กฎหลักเหมือนกัน: ไม่มี Observable หรือ Flowable ใดควรปล่อยข้อมูลจากเธรดหลัก

การตรวจสอบในระบบผลิต

Firebase Crashlytics ตั้งแต่เวอร์ชัน SDK 18.4.0 รองรับการตรวจสอบ ANR แบบพร้อมใช้งานทันที สำหรับ Android 11+ Crashlytics ใช้ API ระบบ ApplicationExitInfo ซึ่งให้สาเหตุการสิ้นสุดที่แน่นอน: ANR, Crash หรือการฆ่าโดยระบบ เปิดใช้งานคีย์ที่กำหนดเองพร้อมพารามิเตอร์หน้าจอและสถานะสำหรับการวิเคราะห์ตามบริบท

เครื่องมือตรวจจับ ANR

ห้าเครื่องมือ ครอบคลุมทุกขั้นตอนของการทำงานกับ ANR: ตั้งแต่การดีบักบนเวิร์กสเตชันไปจนถึงการตรวจสอบในระบบผลิต แต่ละเครื่องมือแก้ปัญหาของตัวเองและให้ข้อมูลสำหรับสถานการณ์ต่างๆ

เครื่องมือวัตถุประสงค์รูปแบบข้อมูล
StrictModeการตรวจจับระหว่างการพัฒนาLogcat / Exception
ANR Watchdog (Android Studio)การติดตามแบบเรียลไทม์Thread dump + timeline
Google Play ConsoleสถิติรวมANR rate + stack traces
Firebase CrashlyticsการตรวจสอบในระบบผลิตApplicationExitInfo
adb bugreportรายงานระบบที่สมบูรณ์traces.txt + logcat + dmesg

แต่ละเครื่องมือมี ซอกของตัวเอง: StrictMode จับการละเมิดที่ชัดเจนในระยะแรก Crashlytics แสดงความถี่ ANR จริงในหมู่ผู้ใช้ และ adb bugreport ให้ภาพที่สมบูรณ์ที่สุดสำหรับกรณีที่ซับซ้อน รวมเข้าด้วยกันเพื่อความครอบคลุมที่สมบูรณ์

Firebase Performance Monitoring

Firebase Performance ติดตามเวลาตอบสนองของเธรด UI และสร้างร่องรอยโดยอัตโนมัติสำหรับการดำเนินการที่ยาวนานอย่างน่าสงสัย หากเธรดหลักถูกบล็อกนานกว่า 500 มิลลิวินาที Performance จะบันทึกการติดตามที่กำหนดเองพร้อมชื่อของเมธอดที่ก่อให้เกิด ซึ่งช่วยให้ตรวจจับสถานการณ์ ANR โดยไม่ต้องให้ผู้ใช้มีส่วนร่วมและก่อนที่จะกลายเป็นวิกฤต

การรวมกับ Firebase Crashlytics ให้ภาพที่สมบูรณ์: Performance แสดงความช้าลงก่อน ANR และ Crashlytics แสดงการค้างเอง ตั้งค่าการแจ้งเตือนใน Firebase Console สำหรับอัตรา ANR ที่สูงกว่า 0.1% แล้วคุณจะได้รับการแจ้งเตือนเกี่ยวกับปัญหาใหม่ก่อนที่จะมีข้อร้องเรียนจำนวนมากจากผู้ใช้

คำถามที่พบบ่อย

ANR แตกต่างจาก Crash อย่างไร?

ANR คือการค้างที่แอปไม่ตอบสนองแต่ยังคงอยู่ในหน่วยความจำ Crash คือการสิ้นสุดที่ผิดปกติโดยสมบูรณ์พร้อมการออกจากกระบวนการ ANR สามารถ “อยู่รอด” ได้หากระบบหรือผู้ใช้รอการตอบกลับ ในขณะที่ Crash จะยุติแอปเสมอ

สามารถจับ ANR ผ่าน try-catch ได้หรือไม่?

ไม่ ANR ไม่ใช่ข้อยกเว้น Java/Kotlin แต่เป็นสัญญาณระบบในระดับกระบวนการ (SIGQUIT) นักพัฒนาไม่สามารถจัดการมันในโค้ดแอปพลิเคชันได้ วิธีเดียวที่จะตอบสนองต่อ ANR คือวิเคราะห์รายงานหลังจากรีสตาร์ท

ทำไม ANR ปรากฏบนอุปกรณ์บางเครื่องแต่ไม่ปรากฏบนเครื่องอื่น?

ประสิทธิภาพของอุปกรณ์, เวอร์ชัน Android, โหลด CPU และจำนวนกระบวนการพื้นหลังส่งผลต่อโอกาสเกิด ANR บนอุปกรณ์ที่อ่อนแอ การดำเนินการเดียวกันอาจใช้เวลานานกว่า 2–3 เท่า เกินขีดจำกัด 5 วินาที

ขีดจำกัดเวลาของ BroadcastReceiver ก่อน ANR คือเท่าใด?

10 วินาที สำหรับ BroadcastReceiver ปกติใน onReceive() สำหรับบริการเบื้องหน้า ขีดจำกัดคือ 20 วินาที และสำหรับ ContentProvider — ไม่มีขีดจำกัดที่ชัดเจน แต่การบล็อกเธรดหลักนานกว่า 5 วินาทียังคงทำให้เกิด ANR

จะทำอย่างไรถ้า ANR เกิดขึ้นนานๆ ครั้งและไม่สามารถทำซ้ำได้?

เปิดใช้งาน StrictMode ในบิลด์ดีบักทั้งหมด เพิ่มการตรวจสอบผ่าน Firebase Crashlytics และใช้ adb bugreport เมื่อ ANR เกิดขึ้น ANR ที่ไม่สม่ำเสมอมักเกี่ยวข้องกับเงื่อนไขการแข่งขันหรือสถานะเครือข่ายเฉพาะ

สรุป

  • ANR — กลไกระบบ Android ที่ทำงานเมื่อเธรดหลักถูกบล็อกนานกว่า 5 วินาที
  • เธรดหลัก ควรจัดการเฉพาะ UI — การดำเนินการอื่นทั้งหมดถูกย้ายไปยังเธรดพื้นหลัง
  • การวินิจฉัย ANR ทำผ่าน traces.txt, Google Play Console และ Firebase Crashlytics
  • StrictMode ตรวจจับ ANR ที่อาจเกิดขึ้นระหว่างการพัฒนาโดยไม่ต้องรันบนอุปกรณ์จริง
  • Coroutines กับ Dispatchers.IO — วิธีมาตรฐานสำหรับการทำงานแบบอะซิงโครนัสในโปรเจกต์ Android สมัยใหม่
  • BroadcastReceiver ต้องใช้ goAsync() หรือตัวลงทะเบียนพื้นหลังเพื่อทำงานนานกว่า 10 วินาที
  • ANR ในระบบผลิต ถูกตรวจสอบผ่าน Crashlytics และ API ApplicationExitInfo ในตัวบน Android 11 ขึ้นไป

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม