onStop — ẩn Activity trong vòng đời Android

Tác giả: IT Sectr Đã đăng: 2026-03-04 Thời gian đọc: 9 phút

onStop — một phương thức của vòng đời Activity trong Android, được hệ thống gọi khi Activity không còn hiển thị với người dùng. Activity chuyển sang trạng thái Stopped sau khi một Activity mới che phủ hoàn toàn nó, hoặc khi ứng dụng được thu nhỏ. Trong phương thức onStop, nhà phát triển phải dừng hoạt ảnh, giải phóng tài nguyên máy ảnh và cảm biến, lưu bản nháp dữ liệu đã nhập. Theo Android Vitals (Google, 2025), xử lý onStop đúng cách giảm số lượng ANR (Ứng dụng không phản hồi) khi thu nhỏ ứng dụng xuống 35%. Sau onStop, hệ thống có thể gọi onRestart (quay lại màn hình) hoặc onDestroy (kết thúc hoàn toàn). Tài liệu Android Developers về vòng đời Activity mô tả onStop là ranh giới giữa trạng thái hiển thị và không hiển thị.

Những điểm chính

  • onStop — phương thức được gọi khi Activity mất hoàn toàn khả năng hiển thị, nhưng Activity vẫn còn trong bộ nhớ.
  • Sau onStop, Activity chuyển sang trạng thái Stopped — còn trong bộ nhớ, nhưng không hiển thị và không tương tác với người dùng.
  • Hệ thống có thể gọi onRestart → onStart → onResume khi quay lại Activity hoặc onDestroy khi kết thúc.
  • Trong onStop, cần giải phóng tài nguyên: dừng hoạt ảnh, tắt cảm biến và máy ảnh, lưu dữ liệu trung gian.
  • Triển khai onStop đúng cách là yếu tố chính cho sự ổn định của ứng dụng khi đa nhiệm và thu nhỏ.

onStop trong Android là gì?

onStop — một phương thức callback của lớp AppCompatActivity (và lớp tiền nhiệm Activity), được hệ điều hành Android gọi khi Activity không còn hiển thị hoàn toàn cho người dùng. Tại thời điểm này, Activity bị ẩn bởi một Activity khác, cửa sổ hội thoại, trình khởi chạy hệ thống hoặc màn hình khóa. Từ góc nhìn vòng đời, onStop theo sau onPause và báo hiệu rằng Activity không còn hiển thị trên màn hình, mặc dù đối tượng Activity và trạng thái của nó vẫn còn trong bộ nhớ.

Khi Activity chuyển sang trạng thái Stopped (đã dừng), nó giữ trạng thái trong RAM — tất cả các trường, phân cấp View và ViewModel vẫn có thể truy cập được. Điều này phân biệt Stopped với trạng thái Destroyed (đã hủy), nơi Activity bị xóa hoàn toàn. Giao diện hệ thống có thể tiến trình ứng dụng ở trạng thái Stopped khi thiếu bộ nhớ — đây gọi là tiến trình bị hủy. Nhà phát triển phải lưu dữ liệu quan trọng (bản nháp, vị trí cuộn) trong onSaveInstanceState(), được gọi trước onStop, để đảm bảo khôi phục khi tiến trình bị hủy.

Theo Tài liệu Định nghĩa Tương thích Android (CDD) cho phiên bản 14+, một tiến trình ở trạng thái Stopped có mức ưu tiên thấp hơn để bị OOM Killer hủy — thấp hơn tiến trình trong giai đoạn Nền, nhưng cao hơn tiến trình được lưu trong bộ nhớ đệm. Theo thống kê của Google, 68% trường hợp tiến trình bị hủy xảy ra khi Activity ở trạng thái Stopped, không phải Paused.

Khi nào onStop được gọi: kịch bản và thứ tự

onStop được gọi khi Activity mất hoàn toàn khả năng hiển thị, bất kể lý do: khởi chạy Activity mới phía trên Activity hiện tại, thu nhỏ ứng dụng (nhấn Home), khóa màn hình, cuộc gọi đến hoặc mở hộp thoại hệ thống. Trong tất cả các trường hợp này, Activity trước tiên nhận onPause (mất tiêu điểm một phần), sau đó onStop (mất hoàn toàn khả năng hiển thị).

Các kịch bản chính gọi onStop:

  • Khởi chạy Activity mới phía trên Activity hiện tại — Activity hiện tại nhận onPause, sau đó onStop; Activity mới trải qua onCreate → onStart → onResume.
  • Thu nhỏ ứng dụng (Home) — Activity chuyển sang onPause → onStop trong 200–300 ms, vẫn ở trong bộ nhớ ở trạng thái Stopped.
  • Khóa màn hình — hệ thống gọi onPause → onStop vì màn hình khóa che phủ hoàn toàn Activity.
  • Cuộc gọi đến — ứng dụng điện thoại (Dialer) khởi chạy phía trên, Activity hiện tại chuyển sang onStop.
  • Chuyển sang ứng dụng khác (Ứng dụng gần đây) — Activity bị ẩn, nhận onStop, nhưng vẫn ở trong bộ nhớ đệm tiến trình.

Điều quan trọng là hiểu rằng onStop không được gọi khi xoay màn hình — trong trường hợp này, Activity bị hủy (onPause → onStop → onDestroy) và được tạo lại (onCreate → onStart → onResume). Ngoại lệ là cờ android:configChanges="orientation" trong tệp kê khai, ngăn không cho Activity được tạo lại và thay vào đó gọi onConfigurationChanged().

onStop trong vòng đời Activity

onStop chiếm vị trí trung tâm trong chuỗi vòng đời Activity giữa trạng thái hiển thị và không hiển thị. Chuỗi đầy đủ: onCreate → onStart → onResume → (trạng thái hoạt động) → onPause → onStop → onDestroy (hoặc onRestart → onStart → onResume khi quay lại).

Trạng tháiPhương thứcHiển thịTương tácBộ nhớ
CreatedonCreateKhôngKhôngĐược cấp phát
StartedonStartMột phầnKhôngĐầy đủ
ResumedonResumeĐầy đủĐầy đủ
PausedonPauseMột phầnKhôngĐầy đủ
StoppedonStopKhôngKhôngĐầy đủ*
DestroyedonDestroyKhôngKhôngĐã giải phóng

*Ở trạng thái Stopped, Activity được giữ trong bộ nhớ nhưng có thể bị hệ thống hủy khi thiếu tài nguyên. Mức ưu tiên hủy tiến trình Stopped là thứ hai từ cuối, chỉ trên các tiến trình trống được lưu trong bộ nhớ đệm.

onStop và onSaveInstanceState: Hệ thống gọi onSaveInstanceState(Bundle) trước onStop để lưu trạng thái giao diện động. Nhà phát triển ghi đè phương thức này để lưu giá trị trường nhập liệu, vị trí RecyclerView và các mục đã chọn vào Bundle. Ngay cả khi Activity không bị hủy (người dùng chỉ thu nhỏ và quay lại), Bundle được chuyển đến onCreate khi thay đổi cấu hình. Google khuyến nghị chỉ lưu trạng thái giao diện tạm thời — không phải dữ liệu kho lưu trữ hoặc ViewModel, những thứ tồn tại bên ngoài Activity.

Những tài nguyên cần giải phóng trong onStop

Trong onStop, nhà phát triển phải giải phóng tất cả tài nguyên không cần thiết khi Activity không hiển thị. Điều này giảm tải cho pin, CPU và bộ nhớ, đồng thời ngăn ANR khi quay lại Activity.

Những gì cần giải phóng trong onStop:

  • Hoạt ảnh và chuyển tiếp — dừng ObjectAnimator, ValueAnimator, ViewPropertyAnimator. Hoạt ảnh đang chạy trên Activity không hiển thị lãng phí chu kỳ GPU.
  • Cảm biến — hủy đăng ký SensorManager (gia tốc kế, con quay hồi chuyển, từ kế). Cảm biến tiêu thụ năng lượng ngay cả khi Activity bị ẩn.
  • Máy ảnh và micrô — giải phóng Camera2 hoặc CameraX, dừng MediaRecorder. Để máy ảnh hoạt động khi Activity bị ẩn bị chính sách Google Play cấm.
  • LocationListener — hủy đăng ký FusedLocationProviderClient hoặc LocationManager. Định vị địa lý là tài nguyên tiêu thụ nhiều năng lượng nhất.
  • Trình lắng nghe mạng — đóng WebSocket, hủy các yêu cầu HTTP không cần thiết trong nền.
  • MediaPlayer và ExoPlayer — tạm dừng hoặc dừng phát lại nếu không nên tiếp tục trong nền.

Không nên làm gì trong onStop: Không thực hiện các thao tác kéo dài — lưu lượng lớn dữ liệu vào cơ sở dữ liệu, yêu cầu mạng, tính toán phức tạp. onStop chạy trên luồng chính và chặn việc quay lại Activity. Đối với các thao tác kéo dài, hãy sử dụng WorkManager có độ trễ hoặc coroutine trong viewModelScope. Không giải phóng tài nguyên ViewModel — ViewModel tồn tại sau onStop và sẽ được sử dụng khi quay lại.

Sự khác biệt giữa onStop và onPause

onPause và onStop khác nhau về mức độ mất khả năng hiển thị và phạm vi các hành động bắt buộc. onPause được gọi khi mất tiêu điểm một phần (ví dụ: mở cửa sổ hội thoại hoặc menu hệ thống), onStop — khi mất hoàn toàn khả năng hiển thị. Sự khác biệt này rất quan trọng để chọn tài nguyên cần giải phóng ở mỗi giai đoạn.

Đặc điểmonPauseonStop
Mức hiển thịHiển thị một phầnHoàn toàn không hiển thị
Tiêu điểmĐã mấtĐã mất
Thời gian thực thiLên đến 500 msLên đến 5 giây (thời gian chờ ANR)
Tài nguyên cần giải phóngQuan trọng (phương tiện, máy ảnh)Tất cả không hiển thị (cảm biến, hoạt ảnh, vị trí)
Khôi phụconResumeonRestart → onStart → onResume
Mức ưu tiên tiến trìnhCao (Tiền cảnh)Trung bình (Nền)

Nguyên tắc chung: trong onPause, giải phóng tài nguyên hệ thống ảnh hưởng ngay lập tức đến trải nghiệm người dùng của ứng dụng khác (máy ảnh, trình phát đa phương tiện); trong onStop — tất cả tài nguyên khác không cần thiết khi Activity bị ẩn. Google khuyến nghị lưu dữ liệu người dùng quan trọng (bản nháp email, cài đặt) trong onPause, vì onStop có thể không được gọi trong quá trình chuyển đổi nhanh.

onStop → onRestart: quay lại màn hình

Khi người dùng quay lại Activity bị ẩn, hệ thống gọi onRestart → onStart → onResume. Phương thức onRestart báo hiệu rằng Activity đang quay lại từ trạng thái Stopped. Đây là giai đoạn quan trọng để khôi phục giao diện và tài nguyên đã được giải phóng trong onStop.

Chuỗi lệnh gọi khi quay lại:

  • onRestart() — Activity được thông báo rằng nó sẽ được hiển thị lại. Các hành động điển hình: tải lại dữ liệu, cập nhật danh sách.
  • onStart() — Activity trở nên hiển thị nhưng chưa hoạt động. Tại đây, các tài nguyên đã giải phóng trong onStop được khởi tạo lại.
  • onResume() — Activity nhận được tiêu điểm và sẵn sàng tương tác. Hoạt ảnh bắt đầu, cảm biến được đăng ký.

Nếu tiến trình ứng dụng bị hệ thống hủy ở trạng thái Stopped, onCreate được gọi thay vì onRestart, và Bundle từ onSaveInstanceState được chuyển để khôi phục trạng thái. Kịch bản này (tiến trình bị hủy) là một trong những nguyên nhân phổ biến nhất gây lỗi trong ứng dụng Android: nhà phát triển triển khai onRestart nhưng quên xem xét khôi phục qua onCreate sau khi tiến trình bị hủy.

Ví dụ mã với onStop trong Kotlin

Ví dụ 1: Triển khai onStop cơ bản với giải phóng cảm biến

Thể hiện việc hủy đăng ký cảm biến đúng cách và dừng hoạt ảnh khi ẩn Activity. Khi quay lại màn hình, tài nguyên được khôi phục trong onStart.

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private var rotationAnimator: ObjectAnimator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    }

    override fun onStart() {
        super.onStart()
        accelerometer?.let {
            sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
        rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
        rotationAnimator?.apply {
            duration = 3000
            repeatMode = ValueAnimator.RESTART
            repeatCount = ValueAnimator.INFINITE
            start()
        }
    }

    override fun onStop() {
        super.onStop()
        sensorManager.unregisterListener(sensorListener)
        rotationAnimator?.cancel()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d("MainActivity", "Activity quay lại từ trạng thái Stopped")
    }

    private val sensorListener = SensorEventListener { event, _ ->
        Log.d("MainActivity", "Gia tốc: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
    }
}

Mã đăng ký cảm biến gia tốc kế và bắt đầu hoạt ảnh xoay vô hạn trong onStart. Trong onStop, cảm biến được hủy đăng ký và hoạt ảnh bị hủy — điều này ngăn tiêu hao pin khi Activity bị ẩn. Sau khi quay lại qua onRestart → onStart, tài nguyên được tạo lại.

Ví dụ 2: onStop với bảo toàn trạng thái qua SavedStateHandle

Cách tiếp cận hiện đại sử dụng ViewModel + SavedStateHandle. Dữ liệu biểu mẫu được tự động lưu trong onStop mà không cần xử lý Bundle thủ công.

kotlin
class FormViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    var email: String
        get() = savedStateHandle["email"] ?: ""
        set(value) { savedStateHandle["email"] = value }

    var message: String
        get() = savedStateHandle["message"] ?: ""
        set(value) { savedStateHandle["message"] = value }
}

class FormActivity : AppCompatActivity() {
    private val viewModel: FormViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_form)
        Log.d("FormActivity", "onCreate: email=${viewModel.email}")
    }

    override fun onStop() {
        super.onStop()
        Log.d("FormActivity", "onStop: dữ liệu đã lưu trong SavedStateHandle")
    }
}

SavedStateHandle tự động lưu giá trị vào Bundle trong onSaveInstanceState, được gọi trước onStop. Khi xoay màn hình hoặc tiến trình bị hủy, dữ liệu được khôi phục mà không mất mát. Google khuyến nghị SavedStateHandle cho biểu mẫu và bản nháp thay vì onSaveInstanceState trực tiếp.

Ví dụ 3: lifecycleScope cho các thao tác trong onStop

Sử dụng lifecycleScope với coroutine để lưu dữ liệu không đồng bộ trong quá trình chuyển sang onStop. Coroutine chạy trên bộ điều phối IO mà không chặn luồng chính.

kotlin
class NoteActivity : AppCompatActivity() {
    private val noteRepository = NoteRepository()

    override fun onStop() {
        lifecycleScope.launch(Dispatchers.IO) {
            val text = findViewById<EditText>(R.id.note_content).text.toString()
            noteRepository.saveDraft(text)
            withContext(Dispatchers.Main) {
                Log.d("NoteActivity", "Bản nháp đã lưu trong onStop")
            }
        }
        super.onStop()
    }
}

Coroutine lifecycleScope.launch tự động bị hủy nếu vòng đời Activity kết thúc. Sử dụng Dispatchers.IO đảm bảo rằng việc ghi vào cơ sở dữ liệu hoặc tệp không chặn việc quay lại Activity. Theo Google, coroutine trong lifecycleScope là cách ưu tiên để thực hiện các thao tác không đồng bộ trong onStop.

Các câu hỏi thường gặp

onStop khác onDestroy như thế nào?

onStop — Activity không còn hiển thị nhưng vẫn ở trong bộ nhớ ở trạng thái Stopped. Hệ thống có thể đưa Activity trở lại qua onRestart. onDestroy — Activity bị hủy, bộ nhớ được giải phóng. Sau onDestroy, chỉ có thể quay lại bằng cách tạo phiên bản Activity mới (onCreate).

Có bắt buộc phải gọi super.onStop() không?

Có, bắt buộc. super.onStop() đảm bảo hoạt động chính xác của các thành phần hệ thống: fragment, LoaderManager, ViewModelStore. Bỏ qua super.onStop() có thể gây rò rỉ bộ nhớ và khôi phục fragment không chính xác. Luôn gọi super.onStop() ở cuối hoặc đầu — thứ tự không quan trọng, nhưng việc gọi là bắt buộc.

Làm thế nào để kiểm tra onStop đã được gọi?

Sử dụng Log.d hoặc Timber trong mỗi phương thức vòng đời. Bật bộ lọc logcat theo thẻ Activity của bạn. Cho môi trường sản xuất, sử dụng Android Vitals — Google tự động thu thập số liệu vòng đời và hiển thị bất thường trong Play Console. Giám sát vòng đời cũng có sẵn qua ProcessLifecycleOwner.

Điều gì xảy ra nếu ngoại lệ được ném trong onStop?

Ngoại lệ không được bắt trong onStop gây ra Force Close ứng dụng. Hệ thống không bắt ngoại lệ trong callback vòng đời. Nếu onStop thực hiện các thao tác có thể ném ngoại lệ (thao tác tệp, mạng), hãy bọc chúng trong try-catch và ghi nhật ký lỗi mà không làm gián đoạn super.onStop().

Có cần giải phóng Bitmap trong onStop không?

Không, Bitmap trong Activity sẽ được GC thu gom nếu không có tham chiếu đến nó. Giải phóng cưỡng bức (recycle()) trong onStop là không cần thiết và thậm chí có hại — nếu Activity quay lại qua onRestart, Bitmap sẽ phải được tải lại. Sử dụng Glide hoặc Coil để tải hình ảnh — các thư viện này tự động quản lý bộ nhớ đệm và vòng đời.

Tổng kết

  • onStop — phương thức vòng đời Activity được gọi khi mất hoàn toàn khả năng hiển thị. Activity vẫn ở trong bộ nhớ ở trạng thái Stopped.
  • Sau onStop, hai kịch bản có thể xảy ra: onRestart (quay lại màn hình) hoặc onDestroy (hủy Activity).
  • Trong onStop, bạn phải giải phóng cảm biến, hoạt ảnh, máy ảnh, trình lắng nghe vị trí — mọi thứ không cần thiết khi Activity không hiển thị.
  • onStop khác onPause ở mức hiển thị: onPause — mất một phần, onStop — mất hoàn toàn khả năng hiển thị.
  • onSaveInstanceState được gọi trước onStop — hãy sử dụng nó để lưu trạng thái giao diện tạm thời.
  • Coroutine lifecycleScope với Dispatchers.IO — cách ưu tiên cho các thao tác không đồng bộ trong onStop.
  • Luôn gọi super.onStop() và bọc các thao tác nguy hiểm trong try-catch để tránh Force Close.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm