Activity
1. Giới thiệu
Lớp Activity là một thành phần quan trọng của ứng dụng Android, và cách các activity được khởi chạy và kết hợp với nhau là một phần cơ bản trong mô hình ứng dụng của nền tảng Android. Khác với các mô hình lập trình khác nơi ứng dụng được khởi chạy bằng phương thức main(), hệ thống Android khởi tạo code trong một instance của Activity bằng cách gọi các callback methods tương ứng với các giai đoạn cụ thể trong vòng đời của nó.
Activity là gì? Activity là một màn hình đơn lẻ với giao diện người dùng. Một ứng dụng email có thể có một activity hiển thị danh sách email mới, một activity khác để soạn email, và một activity khác để đọc email.
2. Khái niệm về Activity
Trải nghiệm ứng dụng di động khác với desktop ở chỗ tương tác của người dùng với ứng dụng không phải lúc nào cũng bắt đầu từ cùng một nơi. Thay vào đó, hành trình của người dùng thường bắt đầu một cách không xác định. Ví dụ:
- Nếu bạn mở ứng dụng email từ màn hình chính, bạn có thể thấy danh sách email
- Nếu bạn đang sử dụng ứng dụng mạng xã hội và nó khởi động ứng dụng email, bạn có thể đi thẳng đến màn hình soạn email
Lớp Activity được thiết kế để hỗ trợ mô hình này. Khi một ứng dụng gọi ứng dụng khác, ứng dụng gọi sẽ gọi một activity trong ứng dụng kia, thay vì toàn bộ ứng dụng. Theo cách này, activity đóng vai trò là điểm vào (entry point) cho tương tác của ứng dụng với người dùng.
Đặc điểm chính của Activity
| Đặc điểm | Mô tả |
|---|---|
| Window | Activity cung cấp cửa sổ để ứng dụng vẽ UI |
| Full-screen | Thường chiếm toàn bộ màn hình, nhưng có thể nhỏ hơn (floating windows) |
| Multi-window | Có thể hiển thị trong chế độ đa cửa sổ |
| One screen | Thông thường, một activity triển khai một màn hình trong ứng dụng |
public class Activity
extends ContextThemeWrapper
implements ComponentCallbacks2, KeyEvent.Callback,
LayoutInflater.Factory2, View.OnCreateContextMenuListener,
Window.Callback3. Activity Stack
Các activity trong hệ thống được quản lý như activity stacks. Khi một activity mới được khởi chạy, nó thường được đặt lên trên cùng của stack hiện tại và trở thành running activity — activity trước đó luôn nằm bên dưới trong stack và sẽ không quay lại foreground cho đến khi activity mới kết thúc.
4 trạng thái của Activity
| Trạng thái | Mô tả |
|---|---|
| Active/Running | Activity ở foreground của màn hình (vị trí cao nhất của stack). Đây là activity mà người dùng đang tương tác. |
| Visible | Activity đã mất focus nhưng vẫn hiển thị với người dùng. Điều này xảy ra khi một activity không full-screen hoặc trong suốt nằm trên activity của bạn. |
| Stopped/Hidden | Activity bị che hoàn toàn bởi activity khác. Nó vẫn giữ tất cả state và thông tin, nhưng không còn hiển thị cho người dùng và thường bị hệ thống kill khi cần bộ nhớ. |
| Destroyed | Hệ thống có thể huỷ activity khỏi bộ nhớ bằng cách yêu cầu nó finish, hoặc đơn giản là kill process của nó. Khi hiển thị lại cho người dùng, activity phải được khởi động lại hoàn toàn. |
4. Khai báo Activity trong Manifest
Để ứng dụng có thể sử dụng activity, bạn phải khai báo activity và một số thuộc tính của nó trong AndroidManifest.xml.
Khai báo cơ bản
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >Không thay đổi tên activity sau khi publish app! Nếu bạn làm vậy, một số chức năng có thể bị hỏng, chẳng hạn như app shortcuts.
Khai báo Main Activity
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>Khai báo Intent Filters
Intent filters cho phép khởi chạy activity dựa trên cả yêu cầu explicit lẫn implicit:
- Explicit: “Khởi động activity Send Email trong ứng dụng Gmail”
- Implicit: “Khởi động màn hình Send Email trong bất kỳ activity nào có thể thực hiện công việc này”
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>Khai báo Permissions
<!-- Activity yêu cầu permission để được gọi -->
<activity
android:name=".ShareActivity"
android:permission="com.myapp.permission.SHARE_POST" />5. Tạo Activity cơ bản
Với Jetpack Compose (Recommended)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello, $name!",
modifier = modifier
)
}Với XML Views (Legacy)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Sử dụng findViewById để lấy views
val textView = findViewById<TextView>(R.id.textView)
textView.text = "Hello, Android!"
}
}6. Ba Vòng đời quan trọng
Activity có 3 key loops bạn cần quan tâm:
Entire Lifetime
Xảy ra giữa lần gọi đầu tiên onCreate() đến lần gọi cuối cùng onDestroy().
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Setup "global" state, tạo background thread
}
override fun onDestroy() {
super.onDestroy()
// Release tất cả resources
}Visible Lifetime
Xảy ra giữa onStart() và onStop(). Trong thời gian này, người dùng có thể thấy activity trên màn hình.
override fun onStart() {
super.onStart()
// Register BroadcastReceiver để monitor UI changes
}
override fun onStop() {
super.onStop()
// Unregister BroadcastReceiver
}Foreground Lifetime
Xảy ra giữa onResume() và onPause(). Trong thời gian này, activity đang visible, active và tương tác với người dùng.
override fun onResume() {
super.onResume()
// Activity đang tương tác với user
}
override fun onPause() {
super.onPause()
// Pause operations, nhưng code nên lightweight
}7. Khởi động Activity khác
Sử dụng Intent
// Explicit Intent
val intent = Intent(this, DetailActivity::class.java).apply {
putExtra("user_id", 123)
putExtra("user_name", "Alice")
}
startActivity(intent)Nhận dữ liệu
class DetailActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val userId = intent.getIntExtra("user_id", 0)
val userName = intent.getStringExtra("user_name") ?: ""
setContent {
DetailScreen(userId, userName)
}
}
}Implicit Intent
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, textMessage)
}
startActivity(sendIntent)8. Kết thúc Activity
// Kết thúc Activity hiện tại
finish()
// Kết thúc và xóa toàn bộ task stack
finishAffinity()
// Kết thúc với result
setResult(Activity.RESULT_OK, Intent().apply {
putExtra("result", "Success")
})
finish()9. Launch Modes
<!-- standard: Mặc định, Activity mới được thêm vào stack -->
<activity android:launchMode="standard" ... />
<!-- singleTop: Tái sử dụng nếu đã ở top của stack -->
<activity android:launchMode="singleTop" ... />
<!-- singleTask: Một instance duy nhất trong task -->
<activity android:launchMode="singleTask" ... />
<!-- singleInstance: Task riêng biệt, instance duy nhất -->
<activity android:launchMode="singleInstance" ... />10. Activity với ViewModel
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val uiState by viewModel.uiState.collectAsState()
MainScreen(
state = uiState,
onEvent = viewModel::onEvent
)
}
}
}ViewModel survive qua configuration changes (như xoay màn hình), trong khi Activity bị destroy và recreate. Vì vậy, hãy đặt UI data trong ViewModel thay vì Activity.
📝 Tóm tắt
| Khái niệm | Mô tả |
|---|---|
| Activity | Thành phần UI cơ bản, đại diện cho một màn hình |
| Entry Point | Activity là điểm vào cho tương tác với người dùng |
| Activity Stack | Các activity được quản lý trong stack (LIFO) |
| 4 States | Active, Visible, Stopped, Destroyed |
| Manifest | Activity phải được khai báo trong AndroidManifest.xml |
| Intent Filters | Cho phép activity respond với implicit intents |
📚 Tham khảo: