Global Exception Handler: สาระสำคัญ หลักการทำงาน และการนำไปใช้ในโปรเจกต์

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

Global Exception Handler — กลไกแบบรวมศูนย์สำหรับการดักจับข้อยกเว้นที่ไม่ได้รับการจัดการ ป้องกันการปิดตัวของแอปพลิเคชันมือถือโดยไม่คาดคิด ตามข้อมูลจาก Apple Developer, 2024 การจัดการข้อยกเว้นที่ถูกต้องช่วยลดจำนวนการขัดข้องลง 40–60% และปรับปรุงประสบการณ์ผู้ใช้ หากไม่มีตัวจัดการดังกล่าว ข้อยกเว้นที่ไม่ได้รับการจัดการในเธรดพื้นหลังจะนำไปสู่การปิดแอปทันที

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

  • Global Exception Handler — จุดรวบรวมกลางของข้อยกเว้นที่ไม่ได้รับการจัดการทั้งหมดในแอป ป้องกันการขัดข้อง
  • iOS NSSetUncaughtExceptionHandler — ฟังก์ชัน C สำหรับการดักจับข้อยกเว้น Objective-C บนแพลตฟอร์ม Apple
  • Android Thread.setDefaultUncaughtExceptionHandler — กลไกในตัวของแพลตฟอร์มสำหรับการดักจับข้อยกเว้นระดับโลก
  • การบันทึกก่อนปิด — งานหลักของตัวจัดการ: บันทึกข้อมูลเกี่ยวกับการขัดข้องก่อนที่กระบวนการจะสิ้นสุด
  • การลดทอนอย่างค่อยเป็นค่อยไป — ตัวจัดการช่วยให้แสดงหน้าจอข้อผิดพลาดที่เหมาะสมแทนการปิดอย่างกระทันหัน

Global Exception Handler คืออะไร?

Global Exception Handler — เป็นกลไกแบบรวมศูนย์สำหรับการดักจับข้อยกเว้นที่ไม่ได้รับการจัดการในระดับฟังก์ชันหรือโมดูลแต่ละรายการของแอปพลิเคชัน ในบริบทของการพัฒนาโมบายล์ ตัวจัดการดังกล่าวทำหน้าที่เป็นแนวป้องกันสุดท้ายก่อนที่กระบวนการจะสิ้นสุดอย่างผิดปกติ

iOS และ Android มี API ในตัวสำหรับการตั้งค่าตัวจัดการระดับโลก Apple ใช้ NSSetUncaughtExceptionHandler สำหรับสภาพแวดล้อม Objective-C ในขณะที่ Google มี Thread.setDefaultUncaughtExceptionHandler ใน Java/Kotlin ทั้งสองกลไกดักจับข้อยกเว้นที่ไม่ถูกจับโดยโครงสร้าง try-catch ในทุกเธรดของแอปพลิเคชัน

ตามข้อมูลจาก Crashlytics (Google, 2024) ประมาณ 25% ของการขัดข้อง เกิดจากข้อยกเว้นที่ไม่ได้รับการจัดการในเธรดพื้นหลัง — พื้นที่ที่ Global Exception Handler มีความสำคัญเป็นพิเศษ นักพัฒนามักให้ความสำคัญกับเธรด UI และลืมการทำงานแบบอะซิงโครนัส

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

ตัวจัดการข้อยกเว้นระดับโลกทำงานอย่างไร

กลไกการทำงาน ของ Global Exception Handler ขึ้นอยู่กับการดักจับสัญญาณของระบบปฏิบัติการหรือข้อยกเว้นขณะรันไทม์ เมื่อโค้ดโยนข้อยกเว้นที่ไม่ถูกจับโดยบล็อก try-catch ใด ๆ การควบคุมจะถูกถ่ายโอนไปยังตัวจัดการที่ลงทะเบียนไว้ล่วงหน้า

บน iOS ตัวจัดการจะถูกลงทะเบียนผ่าน NSSetUncaughtExceptionHandler และรับออบเจกต์ NSException พร้อมร่องรอยสแต็กแบบเต็ม บน Android ใช้ Thread.setDefaultUncaughtExceptionHandler ซึ่งรับ Thread และ Throwable — ให้การเข้าถึงประเภทข้อยกเว้น ข้อความ และสแต็กการเรียก

หลังจากรับข้อมูลการขัดข้อง ตัวจัดการจะดำเนินการ สามสิ่งที่จำเป็น: เขียนบันทึกลงในพื้นที่จัดเก็บในเครื่อง ส่งรายงานไปยัง Crashlytics หรือ Sentry และสิ้นสุดแอปพลิเคชันอย่างถูกต้อง ตาม Apple WWDC 2023 เวลาดำเนินการของตัวจัดการถูกจำกัดไว้ที่ 5 วินาที — หลังจากนั้นระบบจะบังคับสิ้นสุดกระบวนการ

สำหรับแอป Swift ตั้งแต่ iOS 13 เป็นต้นมา มีการนำ Signals API มาใช้ ซึ่งจัดการไม่เพียงแต่ข้อยกเว้น แต่ยังรวมถึงสัญญาณของระบบปฏิบัติการ — SIGABRT, SIGSEGV และ SIGBUS ขยายขอบเขตของตัวจัดการไปยังข้อผิดพลาดหน่วยความจำระดับต่ำ

การใช้งาน Global Exception Handler บน iOS

การใช้งาน ตัวจัดการระดับโลกบน iOS จำเป็นต้องตั้งค่าฟังก์ชัน C ผ่าน NSSetUncaughtExceptionHandler ตัวจัดการจะถูกเรียกแบบซิงโครนัสในขณะที่เกิดข้อยกเว้นที่ไม่ได้รับการจัดการและรับบริบทข้อผิดพลาดแบบเต็ม

objective-c
void handleUncaughtException(NSException exception) {
    NSDictionary userInfo = [exception userInfo];
    NSArray stackTrace = [exception callStackSymbols];
    NSString reason = [exception reason];

    // บันทึกบันทึกข้อขัดข้องในไฟล์ท้องถิ่น
    NSString logPath = [NSSearchPathForDirectoriesInDomains(
        NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    [exceptionLog writeToFile:logPath atomically:YES];
}

int main(int argc, char argv[]) {
    NSSetUncaughtExceptionHandler(&handleUncaughtException);
    return UIApplicationMain(argc, argv, nil, nil);
}

คุณสมบัติที่สำคัญ ของการใช้งาน iOS: ตัวจัดการดักจับเฉพาะ ข้อยกเว้น Objective-C เท่านั้น ข้อผิดพลาด Swift ที่ใช้กลไก throw-catch ไม่ถึงตัวจัดการนี้ — ต้องมีการจัดการแยกต่างหากผ่าน Swift Error Handling ตั้งแต่ iOS 14 เป็นต้นไป Apple แนะนำให้รวม NSSetUncaughtExceptionHandler กับ Signals API เพื่อให้ครอบคลุมสูงสุด

ตาม Apple Technical Note TN2151 หลังจากเรียกตัวจัดการแล้ว แอปพลิเคชันต้องสิ้นสุดภายใน 5 วินาที ความพยายามใด ๆ ที่จะดำเนินการต่อหลังจากกลับจากตัวจัดการจะนำไปสู่พฤติกรรมที่ไม่กำหนดและการขัดข้องซ้ำ

การใช้งาน Global Exception Handler บน Android

Android มีกลไกที่ยืดหยุ่นกว่าสำหรับการจัดการข้อยกเว้นระดับโลกผ่าน Thread.setDefaultUncaughtExceptionHandler ตัวจัดการได้รับการอ้างอิงไปยังเธรดที่เกิดข้อยกเว้นและออบเจกต์ Throwable เอง

kotlin
class GlobalExceptionHandler : Thread.UncaughtExceptionHandler {

    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        // บันทึกบันทึกข้อขัดข้องในไฟล์
        val stackTrace = throwable.stackTraceToString()
        val crashLog = "CRASH: ${thread.name}\n${stackTrace}"

        val file = File(context.cacheDir, "crash_log.txt")
        file.writeText(crashLog)

        // ส่งไปยัง Crashlytics
        FirebaseCrashlytics.getInstance()
            .recordException(throwable)

        // สิ้นสุดกระบวนการ
        android.os.Process.killProcess(
            android.os.Process.myPid()
        )
    }
}

// ตั้งค่าใน Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Thread.setDefaultUncaughtExceptionHandler(
            GlobalExceptionHandler()
        )
    }
}

ความแตกต่างที่สำคัญ ของการใช้งาน Android: แต่ละเธรดมีตัวจัดการของตัวเอง และ setDefaultUncaughtExceptionHandler จะตั้งค่าตัวจัดการสำหรับเธรดทั้งหมดที่ไม่มีตัวจัดการเฉพาะรายบุคคลที่กำหนดไว้ ซึ่งรับประกัน ความครอบคลุมระดับโลก — จากเธรด UI ไปจนถึง AsyncTask พื้นหลังและโครูทีน

บน Android 12+ มีข้อจำกัด: หลังจากเรียก uncaughtException แอปพลิเคชันต้องสิ้นสุดภายใน 100 มิลลิวินาที หากตัวจัดการดำเนินการที่ใช้เวลานาน ระบบอาจฆ่ากระบวนการก่อนที่บันทึกจะถูกเขียน ขอแนะนำให้ใช้ บริการพื้นหลัง สำหรับการส่งรายงานการขัดข้อง

แนวทางปฏิบัติที่ดีที่สุดกับ Global Exception Handler

กฎข้อแรก — อย่าพยายามกู้คืนการทำงานของแอปพลิเคชันหลังจากข้อยกเว้นที่ไม่ได้รับการจัดการ สถานะของแอปพลิเคชันหลังการขัดข้องไม่แน่นอน และการดำเนินการต่ออาจนำไปสู่ความเสียหายของข้อมูลผู้ใช้

ลดเวลาในการทำงานของตัวจัดการ

ข้อจำกัดด้านเวลา — ข้อจำกัดทางเทคนิคหลักของ Global Exception Handler บน iOS คือ 5 วินาที บน Android — 100 มิลลิวินาที ภายในตัวจัดการ ควรบันทึกเฉพาะชุดข้อมูลขั้นต่ำ: ประเภทข้อยกเว้น สแต็กการเรียก และสถานะของตัวแปรสำคัญสองสามตัว

การส่งคำขอเครือข่าย การเขียนไปยังฐานข้อมูล และการทำให้เป็นอนุกรมที่ซับซ้อนควรเลื่อนไปยัง กลไกที่เลื่อนออกไป — ตัวอย่างเช่น บันทึกลงในไฟล์และส่งเมื่อเริ่มต้นแอปครั้งถัดไป

การรวมกับระบบรายงานการขัดข้อง

บริการรายงานการขัดข้อง — Firebase Crashlytics, Sentry, Bugsnag — ตั้งค่าตัวจัดการระดับโลกของตัวเอง หากนักพัฒนาตั้งค่าตัวจัดการแบบกำหนดเองเพิ่มเติม พวกเขาต้องส่งต่อการควบคุมไปยังระบบรายงานการขัดข้องหลังจากดำเนินการของตนเอง บน Android ใช้ การประกอบตัวจัดการ: ดำเนินการตรรกะของคุณ จากนั้นเรียกตัวจัดการก่อนหน้า

สำหรับ Firebase Crashlytics ขอแนะนำไม่ให้ตั้งค่า Thread.setDefaultUncaughtExceptionHandler แบบกำหนดเอง — SDK Crashlytics ทำสิ่งนี้โดยอัตโนมัติเมื่อเริ่มต้น

การบันทึกข้อมูลเพิ่มเติม

บริบทผู้ใช้ — นอกเหนือจากสแต็กการเรียกมาตรฐาน ควรบันทึกเวอร์ชันแอป เวอร์ชันระบบปฏิบัติการ ขนาดหน่วยความจำที่ว่าง และเวลาทำงานก่อนการขัดข้อง ข้อมูลนี้มีความสำคัญอย่างยิ่งสำหรับ การทำซ้ำ และแก้ไขปัญหา

บน iOS สามารถใช้ NSSetUncaughtExceptionHandler ไม่เพียงแต่สำหรับการเขียน แต่ยังสำหรับการจัดเก็บข้อมูลชั่วคราวใน NSUserDefaults ด้วยแฟล็ก synchronize — ซึ่งรับประกันความคงอยู่แม้ในกรณีที่กระบวนการสิ้นสุดทันที

การทดสอบตัวจัดการก่อนเผยแพร่

การทดสอบที่จำเป็น — Global Exception Handler ต้องได้รับการทดสอบในทุกขั้นตอนของ CI/CD บน iOS สามารถเริ่มข้อยกเว้นทดสอบผ่าน @throw NSException บน Android — ผ่าน throw RuntimeException() ตรวจสอบว่าตัวจัดการถูกเรียก บันทึกถูกบันทึก และแอปพลิเคชันสิ้นสุดอย่างถูกต้อง

ตาม Google I/O 2023 มากกว่า 30% ของการขัดข้อง ในระบบผลิตเกิดบนอุปกรณ์ที่นักพัฒนาไม่ได้ทดสอบ — เวอร์ชัน Android ที่แตกต่างกัน เฟิร์มแวร์ที่กำหนดเอง หน่วยความจำจำกัด

ข้อผิดพลาดทั่วไปเมื่อใช้ตัวจัดการ

ข้อผิดพลาดแรกและพบบ่อยที่สุด — การพยายามดำเนินการแอปพลิเคชันต่อหลังจากจัดการข้อยกเว้น หลังจากเรียก uncaughtException แอปพลิเคชันอยู่ในสถานะไม่เสถียร และการดำเนินการใด ๆ เพิ่มเติมอาจทำให้เกิด ข้อผิดพลาดแบบลูกโซ่ และความเสียหายของข้อมูล

ข้อผิดพลาดที่สอง — การดำเนินการที่ใช้เวลานานภายในตัวจัดการ คำขอเครือข่าย การเขียนไฟล์ขนาดใหญ่ หรือการคำนวณที่ซับซ้อนไม่เสร็จสิ้นก่อนที่กระบวนการจะถูกบังคับสิ้นสุด ตาม Apple Technical Q&A QA1468 การพยายามส่งคำขอ HTTP ภายในตัวจัดการเป็นสาเหตุหลักของการสูญเสียรายงานการขัดข้อง

ข้อผิดพลาดที่สาม — การละเลยเธรดพื้นหลัง Global Exception Handler ที่ตั้งค่าเฉพาะเธรดหลักไม่ป้องกันการขัดข้องในโครูทีน DispatchQueue AsyncTask หรือ RxJava บน Android แต่ละเธรดควรมีตัวจัดการของตัวเอง — และ setDefaultUncaughtExceptionHandler แก้ไขปัญหานี้เฉพาะสำหรับเธรดที่ไม่มีตัวจัดการเฉพาะรายบุคคล

ข้อผิดพลาดที่สี่ — การไม่มีทางเลือกสำรองสำหรับสัญญาณระบบปฏิบัติการ NSSetUncaughtExceptionHandler บน iOS ไม่ดักจับ SIGABRT, SIGSEGV และ SIGBUS สัญญาณเหล่านี้ต้องการการตั้งค่าตัวจัดการแยกต่างหากผ่าน sigaction API นักพัฒนาจะพบสิ่งนี้ก็ต่อเมื่อแอปขัดข้องโดยไม่มีรายงานการขัดข้องแม้แต่ฉบับเดียว

ข้อผิดพลาดที่ห้า — การบันทึกข้อมูลที่เป็นความลับ บันทึกการขัดข้องอาจมีอีเมล โทเค็นการรับรองความถูกต้อง หรือข้อมูลส่วนบุคคลของผู้ใช้ ซึ่งละเมิด GDPR และ แนวทางการตรวจสอบ App Store ของ Apple กรองข้อมูลที่ส่งผ่านเสมอโดยใช้นิพจน์ปกติหรือรายการที่อนุญาตของฟิลด์ที่อนุญาต

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

สามารถกู้คืนแอปพลิเคชันหลังจากข้อยกเว้นระดับโลกได้หรือไม่?

ไม่ — หลังจากเรียก Global Exception Handler สถานะของแอปพลิเคชันไม่แน่นอน ความพยายามใด ๆ ที่จะดำเนินการต่ออาจนำไปสู่ความเสียหายของข้อมูล การกระทำที่ถูกต้องเพียงอย่างเดียวคือบันทึกบันทึกการขัดข้องและสิ้นสุดกระบวนการ

Global Exception Handler ดักจับข้อผิดพลาดทุกประเภทหรือไม่?

ไม่ทั้งหมด — บน iOS NSSetUncaughtExceptionHandler ดักจับเฉพาะข้อยกเว้น Objective-C ข้อผิดพลาด Swift และสัญญาณระบบปฏิบัติการ (SIGSEGV, SIGABRT) ต้องการตัวจัดการแยกต่างหาก บน Android Thread.setDefaultUncaughtExceptionHandler ดักจับ RuntimeExceptions ทั้งหมด แต่ไม่ใช่ข้อผิดพลาดโค้ดเนทีฟผ่าน JNI

จะส่งต่อการควบคุมไปยังระบบรายงานการขัดข้องหลังจากตัวจัดการของฉันได้อย่างไร?

บันทึกการอ้างอิงไปยัง ตัวจัดการก่อนหน้า ผ่าน Thread.getDefaultUncaughtExceptionHandler() ก่อนตั้งค่าตัวจัดการของคุณ ในตอนท้ายของตัวจัดการของคุณ เรียก previousHandler.uncaughtException(thread, throwable) — สิ่งนี้รับประกันว่า Crashlytics หรือ Sentry จะได้รับข้อมูลของพวกเขา

จะทำอย่างไรหากการขัดข้องเกิดขึ้นในโค้ดเนทีฟ C/C++?

สำหรับโค้ดเนทีฟ จำเป็นต้อง การจัดการสัญญาณ ผ่าน sigaction() — SIGSEGV, SIGABRT, SIGBUS บน Android สามารถใช้ Google Breakpad หรือ Crashpad บน iOS ตั้งแต่เวอร์ชัน 13 เป็นต้นมา มี Signals API สำหรับจัดการข้อยกเว้น mach

Global Exception Handler ส่งผลต่อประสิทธิภาพหรือไม่?

ไม่ — การตั้งค่าตัวจัดการส่งผลเฉพาะช่วงเวลาที่เกิดข้อยกเว้นเท่านั้น ในการทำงานปกติของแอปพลิเคชัน ไม่มีโอเวอร์เฮด ความเสี่ยงเดียวคือ หน่วยความจำรั่ว หากตัวจัดการเก็บการอ้างอิงไปยัง Activity หรือ Context ป้องกันการเก็บขยะ

สรุป

  • Global Exception Handler — แนวป้องกันสุดท้ายก่อนการขัดข้อง จำเป็นในแอปพลิเคชันระบบผลิตทุกตัว
  • iOS NSSetUncaughtExceptionHandler ดักจับข้อยกเว้น Objective-C ด้วยขีดจำกัดการประมวลผล 5 วินาที
  • Android Thread.setDefaultUncaughtExceptionHandler ทำงานสำหรับทุกเธรดที่ไม่มีตัวจัดการส่วนบุคคล
  • เวลาดำเนินการ ของตัวจัดการควรน้อยที่สุด — บันทึกข้อมูลและสิ้นสุดกระบวนการโดยไม่พยายามกู้คืน
  • สัญญาณระบบปฏิบัติการ (SIGSEGV, SIGABRT) ไม่ถูกดักจับโดยตัวจัดการมาตรฐาน — ต้องใช้ sigaction API
  • ระบบรายงานการขัดข้อง ควรเรียกผ่านการประกอบตัวจัดการ ส่งต่อการควบคุมหลังจากตรรกะของคุณ
  • การทดสอบตัวจัดการ ใน CI/CD — ขั้นตอนที่จำเป็นในการป้องกันการสูญเสียรายงานการขัดข้องในระบบผลิต

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

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

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

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