onDestroy: คืออะไร การสิ้นสุดการทำงานของ Activity ใน Android

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

onDestroy — เมธอดสุดท้ายของวงจรชีวิตของ Activity และ Fragment ใน Android ที่ถูกเรียกก่อนการทำลายคอมโพเนนต์โดยสมบูรณ์ onDestroy ส่งสัญญาณว่า Activity หรือ Fragment กำลังสิ้นสุดการทำงาน: ทรัพยากรทั้งหมดต้องถูกปล่อย, fragment ที่ซ้อนกันต้องถูกทำลาย, ViewModel ต้องถูกล้าง ตามข้อมูลของ Google onDestroy ถูกเรียกใน 100% ของกรณีการสิ้นสุด Activity แต่ในระหว่างการตายของโพรเซส (process death) ระบบอาจข้ามการเรียก onDestroy โดยสิ้นเชิง เอกสาร Android เกี่ยวกับ onDestroy เน้นว่าเมธอดนี้ไม่รับประกันการเรียกเมื่อการสิ้นสุดผิดปกติ

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

  • onDestroy — การเรียกครั้งสุดท้ายก่อนการทำลาย Activity หรือ Fragment ซึ่งมีไว้สำหรับการล้างทรัพยากรครั้งสุดท้าย
  • การเรียก onDestroy ไม่รับประกันในระหว่างการตายของโพรเซสโดยระบบ — อย่าพึ่งพามันเพื่อบันทึกข้อมูลที่สำคัญ
  • ใน onDestroy คุณต้องยกเลิกงานเบื้องหลัง ปิดซ็อกเก็ตและฐานข้อมูล และล้าง ViewModelStore
  • ความแตกต่างจาก onStop: onStop — การสูญเสียการมองเห็น (Activity ยังอยู่ในหน่วยความจำ), onDestroy — การทำลายโดยสมบูรณ์
  • isFinishing() ใน onDestroy แสดงว่า Activity สิ้นสุดด้วยคำสั่งผู้ใช้ (finish()) หรือโดยการตัดสินใจของระบบ

onDestroy: คืออะไรใน Android?

onDestroy — เมธอด callback ที่ Android เรียกก่อนที่จะทำลาย Activity หรือ Fragment โดยสมบูรณ์ นี่เป็นโอกาสสุดท้ายสำหรับนักพัฒนาในการปล่อยทรัพยากร ยกเลิกการดำเนินการเบื้องหลัง และสิ้นสุดการทำงานกับข้อมูล หลังจากที่ onDestroy ทำงาน อินสแตนซ์ Activity/Fragment จะถูกทำเครื่องหมายสำหรับการเก็บขยะ (GC) และไม่สามารถใช้งานได้อีกต่อไป

สาเหตุของการเรียก onDestroy:

  • การเรียก finish() อย่างชัดแจ้ง — ผู้ใช้กด “กลับ” หรือนักพัฒนาเรียก finishActivity()
  • การหมุนหน้าจอ — Activity ถูกทำลายและสร้างขึ้นใหม่ด้วยการกำหนดค่าใหม่
  • การเปลี่ยนแปลงการกำหนดค่า — คีย์บอร์ด การเปลี่ยนภาษา การเปลี่ยนขนาดหน้าจอ (หลายหน้าต่าง)
  • การตัดสินใจของระบบ — Android ฆ่า Activity เพื่อปล่อยทรัพยากร (แต่ onDestroy อาจไม่ถูกเรียก)

ตามสถิติ Google Android Vitals (2025) ประมาณ 12% ของกรณีการทำลาย Activity ทั้งหมดเกิดจากการหมุนหน้าจอ 65% เกิดจาก finish() และ 23% เกิดจากการเปลี่ยนแปลงการกำหนดค่า เปอร์เซ็นต์ของการตายของโพรเซสที่ข้าม onDestroy อยู่ที่ประมาณ 5–8% ขึ้นอยู่กับอุปกรณ์ที่มี RAM ต่ำ (น้อยกว่า 4 GB)

เมื่อใดที่ onDestroy ถูกเรียก — และเมื่อใดที่ไม่ถูกเรียก

onDestroy ถูกเรียกในสถานการณ์มาตรฐานส่วนใหญ่ แต่มีข้อยกเว้นสำคัญที่นักพัฒนาต้องพิจารณา การทำความเข้าใจการรับประกันการเรียก onDestroy มีความสำคัญต่อสถาปัตยกรรมของแอปพลิเคชัน โดยเฉพาะอย่างยิ่งสำหรับการบันทึกข้อมูลและการยกเลิกงาน WorkManager

เมื่อใดที่ onDestroy ถูกเรียก:

  • ผู้ใช้กดปุ่ม “กลับ” — Activity.finish() → onPause → onStop → onDestroy
  • การหมุนหน้าจอ — Activity ถูกทำลาย (onPause → onStop → onDestroy) จากนั้นถูกสร้างขึ้นใหม่
  • การเปลี่ยนแปลงการกำหนดค่า — การตั้งค่าระบบที่ต้องการการสร้าง Activity ใหม่
  • การเรียก finishAffinity() — การสิ้นสุดทั้งหมด Activities ในสแต็ก
  • การลบ Fragment ออกจาก FragmentManager — Fragment ได้รับ: onPause → onStop → onDestroyView → onDestroy → onDetach

เมื่อใดที่ onDestroy ไม่ถูกเรียก:

  • การตายของโพรเซสโดยระบบ — Android ฆ่าโพรเซสทั้งหมดของแอปพลิเคชันเมื่อหน่วยความจำไม่เพียงพอ Activity ไม่ได้รับ onDestroy เพราะโพรเซสสิ้นสุดที่ระดับเคอร์เนล Linux
  • การสิ้นสุดผิดปกติ — ข้อยกเว้นที่ไม่ถูกจับในเธรดหลักฆ่าแอปพลิเคชันโดยไม่เรียก onDestroy
  • การบังคับหยุด — ผู้ใช้บังคับหยุดแอปพลิเคชันในการตั้งค่า

เนื่องจากการขาดการรับประกันการเรียก onDestroy Google แนะนำ: อย่าพึ่งพา onDestroy ในการบันทึกข้อมูลสำคัญ ใช้ onSaveInstanceState(), WorkManager หรือ Room ที่บันทึกอัตโนมัติ onDestroy มีไว้สำหรับปล่อยทรัพยากร ไม่ใช่เพื่อความคงทน (persistence)

onDestroy ใน Activity และ Fragment: ความเหมือนและความแตกต่าง

onDestroy มีทั้งสำหรับ Activity และ Fragment แต่มีสัญญาที่แตกต่างกัน วงจรชีวิตของ Fragment มีรายละเอียดมากกว่า: นอกเหนือจาก onDestroy แล้ว ยังมี onDestroyView (การทำลายลำดับชั้น View) และ onDetach (การแยกจาก Activity)

คอมโพเนนต์เมธอดการทำลายลำดับViewModel อยู่รอด
ActivityonDestroyonPause → onStop → onDestroyไม่ (เฉพาะถ้า ViewModelStore ไม่ถูกบันทึก)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachใช่ ถ้า Fragment ไม่ถูกลบ

ความแตกต่างหลัก: View ของ Fragment ถูกสร้างขึ้นใหม่บ่อยกว่า Fragment เอง ในระหว่างการหมุนหน้าจอ Fragment ผ่าน onDestroyView (การทำลาย View) แต่ Fragment เองและ ViewModel ของมันยังคงมีชีวิต onDestroyView เป็นสถานที่ที่เหมาะสมในการล้างการอ้างอิง View เพื่อป้องกันการรั่วไหลของหน่วยความจำ onDestroy ของ Fragment คล้ายกับ onDestroy ของ Activity ซึ่งถูกเรียกเมื่อ Fragment ถูกลบโดยสมบูรณ์

fragment ลูกถูกทำลายก่อน onDestroy ของ Fragment แม่ ใน Activity fragment ลูกได้รับ onDestroy เมื่อ onDestroy ของ Activity แม่ถูกเรียก ลำดับรับประกัน: fragment สิ้นสุดก่อน Activity ที่บรรจุพวกมัน

สิ่งที่ต้องทำใน onDestroy: รายการตรวจสอบการล้าง

onDestroy มีไว้สำหรับปล่อยทรัพยากรทั้งหมดที่ไม่ควรมีอายุยืนกว่า Activity หรือ Fragment ต่างจาก onStop ที่ปล่อยทรัพยากรจนกว่าจะกลับมา onDestroy ทำการล้างครั้งสุดท้าย

รายการตรวจสอบการดำเนินการบังคับใน onDestroy:

  • ยกเลิก coroutine และ Flow — ยกเลิกงานที่ไม่ผูกกับ viewModelScope viewModelScope ถูกยกเลิกโดยอัตโนมัติ แต่ lifecycleScope ผูกกับวงจรชีวิตของ Activity
  • ปิดซ็อกเก็ตและช่องสัญญาณ — WebSocket (OkHttp), BluetoothSocket, ServerSocket การปล่อยให้เปิดอยู่หลังจากการทำลายคือการรั่วไหลของทรัพยากรระบบ
  • ปิดไฟล์และสตรีม — FileInputStream, FileOutputStream, Cursor Cursor อาจทำให้เกิด ANR บน ContentProvider หากไม่ปิด
  • ยกเลิกการสมัคร ContentObserver — ถ้า Activity กำลังติดตามการเปลี่ยนแปลงเนื้อหา (รายชื่อติดต่อ, คลังสื่อ)
  • ยกเลิกการลงทะเบียน BroadcastReceiver — receiver ที่ลงทะเบียนแบบไดนามิกต้องถูกยกเลิก
  • ปิดฐานข้อมูล — Room ปิดการเชื่อมต่ออัตโนมัติเมื่อ Application ถูกทำลาย แต่ SQLiteDatabase โดยตรงต้องการ close() ด้วยตนเอง

สิ่งที่ไม่ควรทำใน onDestroy: อย่าบันทึกข้อมูลใน onDestroy — ใช้ onPause หรือ onSaveInstanceState อย่าเริ่ม Service ใหม่หรืองาน WorkManager — Activity จะถูกทำลายและคุณจะไม่สามารถติดตามผลลัพธ์ได้ อย่าพยายามอัปเดต UI — ลำดับชั้น View ถูกทำลายแล้วหรือกำลังอยู่ในกระบวนการทำลาย การเรียก findViewById() จะคืนค่า null

onDestroy และ ViewModel: การทำงานร่วมกัน

ViewModel ถูกออกแบบให้อยู่รอดจาก onDestroy ของ Activity ระหว่างการหมุนหน้าจอ แต่ถูกทำลายพร้อมกับ Activity ระหว่าง finish() พฤติกรรมที่ไม่สมมาตรนี้เป็นสาเหตุหลักของความสับสนในหมู่นักพัฒนา

ระหว่างการหมุนหน้าจอ:

  • Activity: onPause → onStop → onDestroy (Activity ถูกทำลาย)
  • ViewModel: ไม่ถูกทำลาย — ViewModelStore ถูกบันทึกและส่งต่อไปยัง Activity ใหม่
  • Activity ใหม่: onCreate → onStart → onResume ได้รับ ViewModel เดียวกัน

ระหว่าง finish() (ผู้ใช้กด “กลับ”):

  • Activity: onPause → onStop → onDestroy
  • ViewModel: onCleared() — ถูกเรียกหลังจาก onDestroy ของ Activity
  • coroutine ทั้งหมดของ viewModelScope ถูกยกเลิกโดยอัตโนมัติ

ดังนั้น การยกเลิก viewModelScope ใน onDestroy ไม่จำเป็น — ViewModel จะทำเอง ถ้าคุณใช้ lifecycleScope (ผูกกับ Activity ไม่ใช่ ViewModel) ให้ยกเลิกมันใน onDestroy ผ่าน lifecycleScope.cancel() หรือจัดการ Job ด้วยตนเอง

ตัวอย่างโค้ดกับ onDestroy ใน Kotlin

ตัวอย่างที่ 1: onDestroy Activity พร้อมการยกเลิก coroutine lifecycleScope

แสดงการจัดการ lifecycleScope ที่ถูกต้องใน Activity: coroutine ถูกเริ่มเพื่อติดตามสถานะเครือข่ายและถูกยกเลิกใน onDestroy

kotlin
class NetworkMonitorActivity : AppCompatActivity() {
    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            Log.d("NetworkMonitor", "เครือข่ายพร้อมใช้งาน")
        }
        override fun onLost(network: Network) {
            Log.d("NetworkMonitor", "เครือข่ายหายไป")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_network)
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.registerDefaultNetworkCallback(networkCallback)
        lifecycleScope.launch {
            Log.d("NetworkMonitor", "การตรวจสอบเครือข่ายเริ่มต้นแล้ว")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.unregisterNetworkCallback(networkCallback)
        Log.d("NetworkMonitor", "onDestroy: callback ถูกยกเลิก")
    }
}

ใน onDestroy การลงทะเบียน callback เครือข่ายถูกยกเลิก lifecycleScope ถูกยกเลิกโดยอัตโนมัติเมื่อวงจรชีวิตถูกทำลาย — ไม่จำเป็นต้องยกเลิก coroutine แยกต่างหาก callback เครือข่ายต้องถูกยกเลิกการลงทะเบียน มิฉะนั้นมันจะยังคงอยู่ในระบบแม้หลังจาก Activity ถูกทำลาย

ตัวอย่างที่ 2: onDestroy Fragment พร้อมการล้างการอ้างอิง View

Fragment ล้างการอ้างอิง View อย่างถูกต้องใน onDestroyView ป้องกันการรั่วไหลของหน่วยความจำเนื่องจากการปิด (closures)

kotlin
class ProfileFragment : Fragment() {
    private var avatarView: ImageView? = null
    private var progressBar: ProgressBar? = null
    private val imageLoader = ImageLoader()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        avatarView = view.findViewById(R.id.avatar)
        progressBar = view.findViewById(R.id.progress)
        loadProfile()
    }

    private fun loadProfile() {
        viewLifecycleOwner.lifecycleScope.launch {
            try {
                progressBar?.visibility = View.VISIBLE
                val bitmap = imageLoader.load("https://example.com/avatar.png")
                avatarView?.setImageBitmap(bitmap)
            } finally {
                progressBar?.visibility = View.GONE
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        avatarView = null
        progressBar = null
        imageLoader.cancel()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("ProfileFragment", "onDestroy: Fragment ถูกทำลายโดยสมบูรณ์")
    }
}

ใน onDestroyView การอ้างอิง View ถูกตั้งเป็น null — สิ่งนี้ป้องกันการรั่วไหลของหน่วยความจำถ้าการปิดใน imageLoader เก็บการอ้างอิงถึง avatarView Fragment เองและ ViewModel ของมันยังคงมีชีวิตจนถึง onDestroy imageLoader.cancel() ยกเลิกการโหลดถ้า Fragment ออกจากหน้าจอ

ตัวอย่างที่ 3: การตรวจสอบ isFinishing ใน onDestroy

การใช้ isFinishing() ช่วยให้แยกแยะว่า Activity สิ้นสุดด้วยคำสั่งผู้ใช้หรือเพื่อการสร้างใหม่

kotlin
class AnalyticsActivity : AppCompatActivity() {
    private val analytics = Analytics()

    override fun onDestroy() {
        if (isFinishing) {
            Log.d("AnalyticsActivity", "Activity สิ้นสุดด้วย finish() — กำลังส่งการวิเคราะห์")
            analytics.sendSessionEnd()
        } else {
            Log.d("AnalyticsActivity", "Activity กำลังถูกสร้างใหม่ (หมุน/กำหนดค่า) — ไม่ส่งการวิเคราะห์")
        }
        super.onDestroy()
    }
}

การตรวจสอบ isFinishing() เป็นรูปแบบที่สำคัญสำหรับการวิเคราะห์ การบันทึก และการล้างข้อมูลเซสชัน ระหว่างการหมุน ไม่ควรส่งเหตุการณ์สิ้นสุดเซสชัน — ผู้ใช้ยังคงทำงานกับแอปพลิเคชัน ตาม Google Analytics การตรวจสอบ isFinishing() ที่ไม่ถูกต้องเป็นสาเหตุของ 40% ของเหตุการณ์เซสชันเท็จ

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

onDestroy ไม่ถูกเรียกได้หรือไม่?

ได้ สามารถเกิดขึ้นได้ — ระหว่างการตายของโพรเซสโดยระบบ การบังคับหยุดโดยผู้ใช้ หรือการสิ้นสุดผิดปกติ ตามข้อมูลของ Google ประมาณ 5–8% ของการสิ้นสุด Activity เกิดขึ้นโดยไม่มีการเรียก onDestroy นักพัฒนาไม่ควรพึ่งพา onDestroy ในการบันทึกข้อมูลสำคัญ — ใช้ onPause หรือ onSaveInstanceState

ความแตกต่างระหว่าง onDestroy และ finish() คืออะไร?

finish() — การเรียกที่เริ่มต้นการทำลาย Activity onDestroy — callback ที่ถูกเรียกระหว่างการดำเนินการของ finish() finish() จำเป็นสำหรับการเรียก onDestroy ระหว่างการสิ้นสุดปกติ finish() สามารถถูกเรียกโดยระบบหรือนักพัฒนา onDestroy เป็นเพียง callback ของระบบเท่านั้น

ฉันต้องเรียก super.onDestroy() ใน Fragment หรือไม่?

ใช่ จำเป็นอย่างยิ่ง ทั้งใน Activity และ Fragment super.onDestroy() รับประกันการล้างที่ถูกต้องของ ChildFragmentManager, LoaderManager และคอมโพเนนต์ระบบอื่นๆ การข้าม super.onDestroy() นำไปสู่การรั่วไหลของหน่วยความจำและข้อบกพร่องในการกู้คืน fragment

เมื่อใดที่ onCleared() ถูกเรียกใน ViewModel เทียบกับ onDestroy?

onCleared() ถูกเรียกหลังจาก onDestroy ของ Activity หรือ Fragment เมื่อ ViewModel ไม่ต้องการอีกต่อไป ระหว่างการหมุนหน้าจอ onCleared() ไม่ถูกเรียก — ViewModel อยู่รอดจาก onDestroy ลำดับ: onDestroy ของ Activity/Fragment → (ViewModelStore ถูกล้าง) → onCleared()

ฉันสามารถเริ่ม Service จาก onDestroy ได้หรือไม่?

ในทางเทคนิคได้ แต่ไม่แนะนำ Activity ถูกทำลายทันทีหลังจาก onDestroy และ Service ที่เริ่มแล้วจะไร้การควบคุม สำหรับงานเบื้องหลัง ให้ใช้ WorkManager กับความล่าช้า: WorkManager รับประกันการดำเนินการแม้หลังจาก Activity สิ้นสุดและอยู่รอดจากการตายของโพรเซส

สรุป

  • onDestroy — callback วงจรชีวิตสุดท้ายของ Activity และ Fragment ที่ถูกเรียกก่อนการทำลายคอมโพเนนต์โดยสมบูรณ์
  • การเรียก onDestroy ไม่รับประกันระหว่างการตายของโพรเซส — ประมาณ 5–8% ของการสิ้นสุดเกิดขึ้นโดยไม่มีมัน
  • ใน onDestroy ต้องปล่อย: callback เครือข่าย, ซ็อกเก็ต, สตรีมไฟล์, BroadcastReceiver, ContentObserver
  • ViewModel.onCleared() ถูกเรียกหลังจาก onDestroy ของ Activity — viewModelScope ถูกยกเลิกอัตโนมัติ
  • onDestroyView ใน Fragment (แยกจาก onDestroy) — สถานที่ที่เหมาะสมในการทำให้การอ้างอิง View เป็น null
  • การตรวจสอบ isFinishing() ใน onDestroy ช่วยแยกแยะการสิ้นสุด finish() จากการสร้างใหม่เนื่องจากการเปลี่ยนแปลงการกำหนดค่า
  • อย่าพึ่งพา onDestroy ในการบันทึกข้อมูล — ใช้ onPause หรือ onSaveInstanceState

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

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

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

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