Tóm tắt bài viết
Vòng đời ứng dụng Android mô tả cách hệ thống quản lý quá trình tạo, chạy, tạm dừng, dừng và hủy các ứng dụng và thành phần (như Activity, Service...). Là đơn vị giao diện, Activity có vòng đời bao gồm các phương thức callback chính: onCreate (khởi tạo), onResume (trạng thái tương tác), onPause (mất tiêu điểm) đến onDestroy (dọn dẹp cuối cùng). Service có hai chế độ vòng đời: khởi chạy (onStartCommand) và liên kết (onBind). Hiểu rõ các cơ chế này rất quan trọng để tối ưu quản lý tài nguyên (như giải phóng bộ nhớ), lưu trạng thái và nâng cao trải nghiệm người dùng. Nhà phát triển cần thực hiện các thao tác khởi tạo/dọn dẹp trong callback tương ứng để đảm bảo ứng dụng chạy hiệu quả và ổn định. Tài liệu chính thức cung cấp biểu đồ quy trình vòng đời đầy đủ và ví dụ mã tham khảo.
Vòng đời ứng dụng Android là cách hệ thống quản lý quá trình tạo, chạy, tạm dừng, dừng và hủy ứng dụng (App) cùng các thành phần của nó (như Activity, Service...). Hiểu rõ vòng đời là yếu tố quan trọng để xây dựng ứng dụng Android mạnh mẽ, phản hồi tốt và tiết kiệm tài nguyên.
1. Vòng đời tổng thể của ứng dụng
- Ứng dụng Android không phải lúc nào cũng chạy ở nền trước, mà được hệ thống quản lý động dựa trên tài nguyên và thao tác của người dùng.
- Quá trình ứng dụng có thể bị hệ thống đóng bất cứ lúc nào (như khi bộ nhớ不足), nhưng khi người dùng khởi động lại, hệ thống sẽ cố gắng khôi phục trạng thái trước đó.
2. Vòng đời Activity (thường gặp nhất và sử dụng nhiều nhất)
Activity là đơn vị giao diện của ứng dụng Android. Vòng đời của nó bao gồm một chuỗi các phương thức callback:
Các phương thức vòng đời chính
- onCreate()
- Được gọi khi Activity được tạo (như lần đầu khởi động, chuyển đổi hướng màn hình...).
- Phù hợp để thực hiện khởi tạo (như setContentView, liên kết điều khiển, khởi tạo dữ liệu...).
- onStart()
- Được gọi khi Activity trở nên hiển thị với người dùng (nhưng chưa thể tương tác).
- onResume()
- Được gọi khi Activity nhận được tiêu điểm, có thể tương tác với người dùng.
- Lúc này Activity đang ở trạng thái "hoạt động ở nền trước".
- onPause()
- Được gọi khi Activity mất tiêu điểm nhưng vẫn hiển thị (như hiển thị hộp thoại, chuyển sang Activity mới).
- Phù hợp để lưu dữ liệu tạm, tạm dừng hoạt ảnh, giải phóng tài nguyên đang sử dụng.
- onStop()
- Được gọi khi Activity hoàn toàn không hiển thị (như bị Activity mới che, nhấn nút Home).
- Phù hợp để giải phóng các tài nguyên nặng hơn.
- onRestart()
- Được gọi khi Activity từ trạng thái dừng được khởi động lại (như từ nền trước quay lại).
- onDestroy()
- Được gọi trước khi Activity bị hủy (như finish(), hệ thống thu hồi).
- Phù hợp để thực hiện dọn dẹp cuối cùng.
Biểu đồ quy trình vòng đời
onCreate
↓
onStart
↓
onResume
↑ ↓
onPause
↑ ↓
onStop
↑ ↓
onRestart
↓
onDestroy
Tình huống điển hình
- Khởi động lần đầu: onCreate → onStart → onResume
- Nhấn nút Home: onPause → onStop
- Quay lại nền trước: onRestart → onStart → onResume
- Bị hủy: onPause → onStop → onDestroy
3. Vòng đời Service
Service là thành phần dịch vụ nền, có hai loại chính:
1. Dịch vụ khởi chạy (startService)
- onCreate → onStartCommand (có thể gọi nhiều lần) → onDestroy
2. Dịch vụ liên kết (bindService)
- onCreate → onBind → onUnbind → onDestroy
4. Vòng đời Application
Application là điểm vào của toàn bộ ứng dụng, có vòng đời dài hơn Activity.
- onCreate: Được gọi khi tiến trình ứng dụng được tạo (chỉ gọi một lần)
- onTerminate: Chỉ được gọi trên trình mô phỏng, không được gọi trên thiết bị thực tế
5. Vòng đời Fragment
Vòng đời Fragment tương tự như Activity, nhưng bị ảnh hưởng bởi vòng đời Activity chứa nó.
6. Ứng dụng thực tế của các callback vòng đời
- Khởi tạo/giải phóng tài nguyên (như cơ sở dữ liệu, mạng, cảm biến)
- Lưu/khôi phục trạng thái UI
- Quản lý phát phương tiện đa phương tiện, hoạt ảnh
- Ngăn ngừa rò rỉ bộ nhớ
7. Ví dụ mã (Activity)
public class ManHinhChinh extends AppCompatActivity {
@Override
protected void onCreate(Bundle duLieuLuu) {
super.onCreate(duLieuLuu);
setContentView(R.layout.man_hinh_chinh);
// Khởi tạo
}
@Override
protected void onStart() {
super.onStart();
// Activity hiển thị
}
@Override
protected void onResume() {
super.onResume();
// Activity nhận được tiêu điểm
}
@Override
protected void onPause() {
super.onPause();
// Giải phóng tài nguyên tạm
}
@Override
protected void onStop() {
super.onStop();
// Giải phóng tài nguyên nặng
}
@Override
protected void onDestroy() {
super.onDestroy();
// Dọn dẹp cuối cùng
}
}
8. Tài liệu chính thức
- Tài liệu chính thức về vòng đời Activity Android
- Tài liệu về lớp Application Android
Dưới đây là phần chi tiết về chế độ khởi chạy Activity và mối quan hệ giữa Activity và Fragment.
I. Chế độ khởi chạy Activity (Launch Modes)
Chế độ khởi chạy Activity quyết định cách hệ thống tạo và quản lý thể hiện Activity trong ngăn tác vụ (Task Stack) khi bạn khởi chạy Activity thông qua Intent. Có bốn chế độ khởi chạy chính:
1. standard (chuẩn, mặc định)
- Mỗi lần khởi chạy sẽ tạo một thể hiện Activity mới, đặt vào đỉnh ngăn tác vụ hiện tại.
- Phù hợp cho hầu hết các trang.
Ví dụ trong Manifest:
<activity android:name=".ManHinhChinh"
android:launchMode="standard" />
2. singleTop (tái sử dụng đỉnh ngăn)
- Nếu Activity cần khởi chạy đã có ở đỉnh ngăn, sẽ không tạo thể hiện mới, mà tái sử dụng thể hiện ở đỉnh và gọi lại phương thức
onNewIntent(). - Nếu không ở đỉnh ngăn, vẫn sẽ tạo thể hiện mới.
Ứng dụng: Ví dụ như trang chi tiết tin tức, người dùng có thể thường xuyên mở cùng một tin.
Ví dụ trong Manifest:
<activity android:name=".ManHinhChinh"
android:launchMode="singleTop" />
3. singleTask (tái sử dụng trong ngăn)
- Nếu Activity cần khởi chạy đã có trong ngăn tác vụ hiện tại, hệ thống sẽ xóa tất cả Activity nằm trên nó (finish) và tái sử dụng thể hiện đó (gọi lại
onNewIntent()). - Nếu không có, sẽ tạo thể hiện mới.
Ứng dụng: Ví dụ như trang chính của ứng dụng, tránh tạo nhiều lần.
Ví dụ trong Manifest:
<activity android:name=".ManHinhChinh"
android:launchMode="singleTask" />
4. singleInstance (thể hiện đơn)
- Activity này sẽ chiếm một ngăn tác vụ mới (Task) riêng biệt, và ngăn đó chỉ chứa nó.
- Khi khởi chạy, hệ thống sẽ kiểm tra xem có ngăn tác vụ riêng cho Activity này không, nếu có thì tái sử dụng, nếu không thì tạo mới.
Ứng dụng: Ví dụ như giao diện cuộc gọi, nhắc nhở báo thức...
Ví dụ trong Manifest:
<activity android:name=".ManHinhChinh"
android:launchMode="singleInstance" />
II. Mối quan hệ giữa Activity và Fragment
1. Fragment là gì?
- Fragment là thành phần "mảnh" được giới thiệu trong Android 3.0, có thể hiểu là một đoạn UI có thể tái sử dụng bên trong Activity.
- Một Activity có thể chứa nhiều Fragment.
- Fragment không thể tồn tại độc lập, phải được nhúng trong Activity.
2. Tại sao cần dùng Fragment?
- Thích ứng đa màn hình: Ví dụ như máy tính bảng và điện thoại, máy tính bảng có thể hiển thị nhiều Fragment trong một Activity, điện thoại thì chia thành nhiều Activity.
- Module hóa: Fragment giúp UI và logic dễ quản lý và tái sử dụng hơn.
- Động UI: Có thể thêm, loại bỏ, thay thế Fragment ngay tại thời điểm chạy.
3. Mối quan hệ giữa Activity và Fragment
- Activity là container, Fragment là nội dung.
- Vòng đời Fragment bị ảnh hưởng bởi Activity chứa nó, nhưng cũng có các callback vòng đời riêng.
- Fragment có thể giao tiếp với Activity (thông qua interface, ViewModel...).
4. Ví dụ mã
Thêm Fragment vào Activity:
QuanLyFragment quanLyFragment = getSupportFragmentManager();
GiaoDichFragment giaoDich = quanLyFragment.beginTransaction();
DoanUIFragment doanUI = new DoanUIFragment();
giaoDich.add(R.id.khung_fragment, doanUI);
giaoDich.commit();
Cấu trúc cơ bản của Fragment:
public class DoanUIFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater boCongCu, ViewGroup nhungCha,
Bundle duLieuLuu) {
return boCongCu.inflate(R.layout.layout_doan_ui, nhungCha, false);
}
}
5. So sánh vòng đời
- Vòng đời Activity: onCreate → onStart → onResume → onPause → onStop → onDestroy
- Vòng đời Fragment chi tiết hơn, bao gồm onAttach, onCreate, onCreateView, onActivityCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach
6. Cách thức giao tiếp
- Activity truyền dữ liệu cho Fragment: Thông qua setArguments(Bundle)
- Fragment giao tiếp với Activity: Thông qua callback interface, ViewModel (khuyến nghị)
III. Câu hỏi phỏng vấn/phát triển phổ biến
- Sự khác biệt giữa Activity và Fragment?
- Activity là đơn vị giao diện hoàn chỉnh, Fragment là đoạn UI có thể tái sử dụng, phải phụ thuộc vào Activity.
- Fragment có thể tồn tại độc lập không?
- Không, phải được nhúng trong Activity.
- Fragment phù hợp tình huống nào?
- Trang phức tạp, thích ứng máy tính bảng, UI động, phát triển module hóa.
IV. Tài liệu chính thức
- Tài liệu chính thức về Activity
- Tài liệu chính thức về Fragment
Chúng ta dùng ví dụ hình tượng sinh động để giải thích quy trình khởi chạy Activity, giúp bạn dễ hiểu ngay.
Ví dụ: Khởi chạy Activity giống như "đặt đồ ăn"
Hãy tưởng tượng bạn đang ở nhà (quá trình App) muốn ăn pizza (SecondActivity), bạn cần đặt hàng qua nền tảng giao đồ ăn (hệ thống AMS), cuối cùng shipper (ActivityThread) sẽ giao pizza đến tay bạn (Activity hiển thị).
1. Bạn đặt hàng (startActivity)
Bạn muốn ăn pizza, nên mở ứng dụng giao đồ ăn trên điện thoại, chọn "pizza" và nhấn đặt hàng. Bước này giống như bạn viết trong code:
Intent mucTich = new Intent(this, ManHinhThuHai.class);
startActivity(mucTich);
Bạn nói với hệ thống: Tôi muốn món "SecondActivity" này!
2. Nền tảng nhận đơn (AMS)
Đơn hàng của bạn (Intent) được gửi đến nền tảng giao đồ ăn (AMS, ActivityManagerService). Nền tảng sẽ:
- Kiểm tra món pizza bạn chọn (SecondActivity) có trong menu không (đăng ký trong Manifest).
- Xem bạn đã từng đặt món tương tự chưa (chế độ khởi chạy, ngăn tác vụ).
- Kiểm tra bạn có quyền đặt hàng không (kiểm tra quyền).
3. Phân đơn cho shipper (ApplicationThread)
Nền tảng giao đồ ăn (AMS) quyết định xong, sẽ giao đơn cho shipper phù hợp (ApplicationThread). Nếu nhà bạn (quá trình đích) chưa mở cửa (quá trình chưa khởi động), nền tảng sẽ sắp xếp người mở cửa trước (khởi động tiến trình).
4. Shipper chuẩn bị pizza (ActivityThread)
Shipper (ActivityThread) nhận đơn hàng, bắt đầu làm pizza (tạo thể hiện Activity), và tuân theo quy trình:
- Rửa rau củ (onCreate)
- Nấu ăn (onStart)
- Trình bày (onResume)
5. Pizza được giao đến tay bạn (Activity hiển thị)
Shipper đưa chiếc pizza nóng hổi (giao diện Activity) đến tay bạn (trên màn hình), bạn có thể thưởng thức!
Tóm tắt quy trình
- Bạn đặt hàng (startActivity)
- Nền tảng nhận đơn (AMS xử lý Intent)
- Phân đơn cho shipper (ApplicationThread thông báo cho quá trình đích)
- Shipper làm pizza (ActivityThread tạo và khởi chạy Activity)
- Pizza được giao đến tay bạn (Activity hiển thị trên màn hình)
Điểm chính
- Bạn đặt hàng: chính là khởi tạo Intent.
- Nền tảng nhận đơn: hệ thống AMS điều phối, quyết định cách xử lý.
- Shipper làm pizza: tiến trình ứng dụng thực sự tạo thể hiện Activity.
- Pizza được giao đến tay bạn: giao diện Activity hiển thị ra màn hình.
Tóm tắt hình tượng
Khởi chạy Activity giống như đặt đồ ăn: bạn đặt hàng, nền tảng giao đơn, shipper làm đồ ăn, cuối cùng bạn nhận được đồ ăn. Mỗi bước đều liên kết chặt chẽ, không thể thiếu!
Tiếp tục thảo luận về các bước chi tiết "shipper" làm đồ ăn (vòng đời Activity), hoặc "nền tảng" cách phân bổ đơn hàng (ngăn tác vụ, chế độ khởi chạy)
Chúng ta tiếp tục dùng ví dụ "đặt đồ ăn", lần này giải thích:
- Các bước chi tiết shipper làm đồ ăn (vòng đời Activity)
- Cách nền tảng phân bổ đơn hàng (ngăn tác vụ, chế độ khởi chạy)
I. Các bước chi tiết shipper làm đồ ăn (vòng đời Activity)
Shipper (ActivityThread) nhận đơn hàng, làm đồ ăn không phải là làm ngay lập tức, mà có một quy trình chuẩn. Tương ứng với Activity, đó là các phương thức callback vòng đời.
1. onCreate (chuẩn bị nguyên liệu)
Shipper chuẩn bị tất cả nguyên vật liệu và dụng cụ (khởi tạo giao diện, biến, tài nguyên...).
- onCreate(): Được gọi khi Activity được tạo. Phù hợp để thực hiện khởi tạo, như setContentView, tìm điều khiển, chuẩn bị dữ liệu.
2. onStart (bắt đầu nấu)
Shipper bắt đầu nấu chính thức, cửa bếp cũng mở (Activity hiển thị, nhưng chưa thể tương tác).
- onStart(): Activity sắp hiển thị với người dùng, nhưng chưa thể tương tác.
3. onResume (đưa đồ ăn đến trước mặt bạn)
Shipper đưa món ăn đã làm đến trước mặt bạn, bạn có thể bắt đầu ăn (Activity hiển thị và có thể tương tác).
- onResume(): Activity vào nền trước, người dùng có thể thao tác.
4. onPause (bạn tạm rời bàn ăn)
Bạn có việc đột ngột rời bàn ăn (như có cuộc gọi), shipper tạm dừng dịch vụ, nhưng đồ ăn vẫn còn trên bàn.
- onPause(): Activity mất tiêu điểm, nhưng vẫn hiển thị. Phù hợp để lưu dữ liệu tạm, tạm dừng hoạt ảnh...
5. onStop (dọn dẹp bàn ăn)
Bạn rời nhà hàng, shipper cất đồ ăn, dọn dẹp bàn ăn.
- onStop(): Activity không hiển thị. Phù hợp để giải phóng tài nguyên, dừng thao tác tốn thời gian.
6. onDestroy (đóng cửa bếp)
Bạn ăn xong đi rồi, shipper dọn dẹp sạch sẽ bếp, đóng cửa đi về.
- onDestroy(): Activity bị hủy, giải phóng tất cả tài nguyên.
7. onRestart (bạn quay lại)
Bạn bỗng nhiên lại muốn ăn, quay lại nhà hàng, shipper làm việc lại.
- onRestart(): Activity từ trạng thái dừng được khởi động lại.
Biểu đồ quy trình vòng đời
onCreate
↓
onStart
↓
onResume
↓
[Đang chạy]
↑
onPause
↓
onStop
↓
onDestroy
II. Cách nền tảng phân bổ đơn hàng (ngăn tác vụ, chế độ khởi chạy)
Nền tảng giao đồ ăn (AMS) nhận đơn hàng của bạn, cần quyết định:
- Đơn hàng này là mở bàn mới, hay gộp với đơn hàng trước của bạn?
- Món ăn bạn có cần đặt cùng với món ăn khác không?
Đây chính là ngăn tác vụ (Task) và chế độ khởi chạy (LaunchMode).
1. Ngăn tác vụ (Task Stack)
- Mỗi ngăn tác vụ giống như một bàn ăn, trên bàn có thể có nhiều món (Activity).
- Khi bạn đặt món mới, nền tảng quyết định đặt trên bàn hiện tại hay mở bàn mới.
2. Chế độ khởi chạy (LaunchMode)
Quyết định món ăn mới (Activity) được phục vụ như thế nào:
(1) standard (chuẩn)
- Mỗi lần đặt món, shipper đều làm một món mới, đặt trên bàn hiện tại.
- Phù hợp cho hầu hết tình huống.
(2) singleTop (tái sử dụng đỉnh ngăn)
- Nếu món bạn vừa đặt đã ở trên cùng bàn, shipper sẽ không làm món mới, mà mang món cũ cho bạn.
- Nếu không ở trên cùng, vẫn làm món mới.
(3) singleTask (tái sử dụng trong ngăn)
- Nếu món bạn đặt đã có trên bàn, shipper sẽ xóa hết các món trên nó, chỉ giữ lại món này, và không làm món mới.
- Nếu không có, sẽ làm món mới.
(4) singleInstance (thể hiện đơn)
- Món ăn này chỉ được đặt riêng một bàn, không có món nào khác cùng bàn.
- Phù hợp tình huống đặc biệt, như báo thức, giao diện cuộc gọi...
Tóm tắt hình tượng
- standard: Mỗi lần đặt đều làm món mới.
- singleTop: Nếu vừa có rồi, không làm mới.
- singleTask: Nếu trên bàn có rồi, xóa hết món trên nó đi.
- singleInstance: Món này phải ngồi riêng một bàn.
III. Kết hợp quy trình
- Bạn đặt món (startActivity)
- Nền tảng (AMS) quyết định đặt bàn nào (ngăn tác vụ), làm như thế nào (chế độ khởi chạy)
- Shipper (ActivityThread) làm theo quy trình (vòng đời)
- Bạn nhận được món (Activity hiển thị)
IV. Tổng kết
- Vòng đời: Giống như các bước shipper làm đồ ăn, đảm bảo món ăn tươi ngon, quy trình chuẩn.
- Ngăn tác vụ/chế độ khởi chạy: Giống như nền tảng phân bổ bàn và món, đảm bảo đặt món có trật tự, trải nghiệm mượt mà.