Giới thiệu về hoạt động

Lớp Activity là một thành phần quan trọng của ứng dụng Android và cách các hoạt động được khởi chạy và kết hợp với nhau là một phần cơ bản của mô hình ứng dụng của nền tảng. Không giống như các mô hình lập trình mà trong đó ứng dụng được khởi chạy bằng phương thức main, hệ thống Android khởi tạo mã trong một thực thể Activity bằng cách gọi các phương thức gọi lại cụ thể tương ứng với các giai đoạn cụ thể trong vòng đời của thực thể đó.

Tài liệu này giới thiệu khái niệm về các hoạt động, sau đó cung cấp một số hướng dẫn đơn giản về cách làm việc với các hoạt động đó. Để biết thêm thông tin về các phương pháp hay nhất trong việc xây dựng cấu trúc ứng dụng, hãy xem Hướng dẫn về cấu trúc ứng dụng.

Khái niệm về hoạt động

Trải nghiệm trên ứng dụng di động khác với trải nghiệm trên máy tính ở 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 ở 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 mở một ứng dụng email trên màn hình chính, bạn có thể thấy danh sách email. Ngược lại, nếu đang dùng một ứng dụng mạng xã hội rồi khởi chạy ứng dụng email, bạn có thể chuyển thẳng đến màn hình soạn email của ứng dụng email.

Lớp Activity được thiết kế để hỗ trợ mô hình này. Khi một ứng dụng gọi một ứng dụng khác, ứng dụng gọi sẽ gọi một hoạt động trong ứng dụng kia, thay vì gọi ứng dụng dưới dạng một tổng thể nguyên tử. Nhờ đó, hoạt động này đóng vai trò là điểm truy cập để ứng dụng tương tác với người dùng. Bạn triển khai một hoạt động dưới dạng lớp con của lớp Activity.

Hoạt động cung cấp cửa sổ mà ứng dụng vẽ giao diện người dùng. Cửa sổ này thường lấp đầy màn hình, nhưng có thể nhỏ hơn màn hình và nổi lên trên các cửa sổ khác.

Thông thường, một hoạt động trong ứng dụng được chỉ định là hoạt động chính, đây là màn hình đầu tiên xuất hiện khi người dùng chạy ứng dụng. Trong các ứng dụng Compose hiện đại, đây là hoạt động duy nhất cần thiết, vì hoạt động này lưu trữ các thành phần kết hợp trong một cấu trúc một hoạt động thay vì sở hữu một hệ phân cấp view. Thay vì ứng dụng có nhiều hoạt động cho các màn hình, các thành phần kết hợp trong hoạt động sẽ lưu trữ nhiều đích đến điều hướng.

Để sử dụng các hoạt động trong ứng dụng, bạn phải đăng ký thông tin về các hoạt động đó trong tệp kê khai của ứng dụng và bạn nên biết về vòng đời của hoạt động. Phần còn lại của tài liệu này sẽ giới thiệu những chủ đề này.

Định cấu hình tệp kê khai

Để ứng dụng có thể sử dụng các hoạt động, bạn phải khai báo các hoạt động và một số thuộc tính của chúng trong tệp kê khai.

Khai báo các hoạt động

Để khai báo hoạt động, hãy mở tệp kê khai rồi thêm phần tử <activity> làm phần tử con của phần tử <application>. Ví dụ:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

Thuộc tính bắt buộc duy nhất cho phần tử này là android:name, chỉ định tên lớp của hoạt động. Bạn cũng có thể thêm các thuộc tính xác định đặc điểm của hoạt động, chẳng hạn như nhãn, biểu tượng hoặc giao diện người dùng. Để biết thêm thông tin về những thuộc tính này và các thuộc tính khác, hãy xem tài liệu tham khảo về phần tử <activity>.

Khai báo bộ lọc ý định

Bộ lọc ý định là một tính năng rất mạnh mẽ của nền tảng Android. Chúng cung cấp khả năng chạy một hoạt động không chỉ dựa trên một yêu cầu rõ ràng mà còn dựa trên một yêu cầu ngầm. Ví dụ: một yêu cầu rõ ràng có thể yêu cầu hệ thống "Khởi động hoạt động Gửi email trong ứng dụng Gmail". Ngược lại, một yêu cầu ngầm ẩn sẽ yêu cầu hệ thống "Bắt đầu màn hình Gửi email trong mọi hoạt động có thể thực hiện công việc này". Khi giao diện người dùng hệ thống hỏi người dùng nên dùng ứng dụng nào để thực hiện một tác vụ, đó là bộ lọc ý định đang hoạt động.

Bạn có thể tận dụng tính năng này bằng cách khai báo một thuộc tính <intent-filter> trong phần tử <activity>. Định nghĩa của phần tử này bao gồm một phần tử <action> và một phần tử <category> và/hoặc một phần tử <data> (không bắt buộc). Các phần tử này kết hợp với nhau để chỉ định loại ý định mà hoạt động của bạn có thể phản hồi. Ví dụ: đoạn mã sau đây cho biết cách định cấu hình một hoạt động gửi dữ liệu văn bản và email, đồng thời nhận yêu cầu từ các hoạt động khác để thực hiện 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>
   <intent-filter>
        <action android:name="android.intent.action.SENDTO" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="mailto" />
    </intent-filter>
</activity>

Trong ví dụ này, phần tử <action> chỉ định rằng hoạt động này gửi dữ liệu. Khai báo phần tử <category> dưới dạng DEFAULT cho phép hoạt động nhận các yêu cầu khởi chạy. Phần tử <data> chỉ định loại dữ liệu mà hoạt động này có thể gửi. Đoạn mã sau đây cho biết cách gọi hoạt động được mô tả ở trên để soạn email:

fun composeEmail(addresses: Array<String>, subject: String) {
    val intent = Intent(Intent.ACTION_SENDTO).apply {
        data = Uri.parse("mailto:") // Only email apps handle this.
        putExtra(Intent.EXTRA_EMAIL, addresses)
        putExtra(Intent.EXTRA_SUBJECT, subject)
    }
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
}

Nếu muốn ứng dụng của mình độc lập và không cho phép các ứng dụng khác kích hoạt các hoạt động của ứng dụng, thì bạn không cần bất kỳ bộ lọc ý định nào khác. Những hoạt động mà bạn không muốn cung cấp cho các ứng dụng khác sẽ không có bộ lọc ý định và bạn có thể tự khởi động các hoạt động đó bằng cách sử dụng ý định tường minh. Để biết thêm thông tin về cách các hoạt động của bạn có thể phản hồi ý định, hãy xem bài viết Ý định và bộ lọc ý định.

Xử lý ý định đến

Ví dụ sau đây cho thấy một mẫu để quản lý vòng đời của activity trong khi xử lý nhiều loại ý định: chia sẻ một văn bản, một hình ảnh và nhiều mảng hình ảnh. Bằng cách định tuyến các dữ liệu đầu vào đa dạng này thông qua một hàm handleIntent tập trung, bạn có thể đảm bảo rằng cả thao tác ACTION_SENDACTION_SEND_MULTIPLE đều được phân tích cú pháp chính xác và uỷ quyền cho ViewModel để cập nhật giao diện người dùng phản ứng.

class ExampleActivity : ComponentActivity() {
  private val viewModel: MyViewModel by viewModels()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    handleIntent(intent)
    setContent {
      ComposeApp(viewModel)
    }
  }

  override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent)
    handleIntent(intent)
  }

  private fun handleIntent(intent: Intent?) {
    when (intent?.action) {
      Intent.ACTION_SEND -> {
        if ("text/plain" == intent.type) {
          intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
            viewModel.handleText(it) // Update UI to reflect text being shared
          }
        } else if (intent.type?.startsWith("image/") == true) {
          (intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
            viewModel.handleImage(it) // Update UI to reflect image being shared
          }
        }
      }

      Intent.ACTION_SEND_MULTIPLE -> {
          if (intent.type?.startsWith("image/") == true) {
              intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
                  viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
              }
          } else {
              // Handle other types
          }
      }

      else -> {
          // Handle other intents
      }
    }
  }
}

Khai báo quyền

Bạn có thể dùng thẻ <activity> của tệp kê khai để kiểm soát những ứng dụng có thể bắt đầu một hoạt động cụ thể. Một hoạt động gốc không thể khởi chạy một hoạt động con, trừ phi cả hai hoạt động đều có cùng quyền trong tệp kê khai. Nếu bạn khai báo một phần tử <uses-permission> cho một hoạt động gốc, thì mỗi hoạt động con phải có một phần tử <uses-permission> tương ứng.

Ví dụ: nếu ứng dụng của bạn muốn dùng một ứng dụng giả định có tên là SocialApp để chia sẻ bài đăng trên mạng xã hội, thì chính SocialApp phải xác định quyền mà một ứng dụng gọi nó phải có:

<manifest>
<activity android:name="...."
   android:permission="com.google.socialapp.permission.SHARE_POST"

/>

Sau đó, để được phép gọi SocialApp, ứng dụng của bạn phải khớp với bộ quyền trong tệp kê khai của SocialApp:

<manifest>
   <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>

Để biết thêm thông tin về các quyền và tính bảo mật nói chung, hãy xem Danh sách kiểm tra bảo mật.

Quản lý vòng đời của activity

Trong vòng đời của mình, một hoạt động sẽ trải qua một số trạng thái. Bạn sử dụng một loạt lệnh gọi lại để xử lý các hiệu ứng chuyển đổi giữa các trạng thái. Các phần sau đây sẽ giới thiệu những lệnh gọi lại này. Trong ứng dụng Compose, bạn không nên liên kết trực tiếp vào các lệnh gọi lại này. Thay vào đó, hãy sử dụng Lifecycle API để theo dõi các thay đổi về trạng thái. Để biết thêm thông tin, hãy xem bài viết Tích hợp vòng đời với Compose.

onCreate

Bạn phải triển khai lệnh gọi lại này. Lệnh gọi lại này sẽ kích hoạt khi hệ thống tạo hoạt động của bạn. Quy trình triển khai của bạn phải khởi tạo các thành phần thiết yếu của hoạt động: Ví dụ: ứng dụng của bạn phải tạo các khung hiển thị và liên kết dữ liệu với danh sách tại đây.

Trong ứng dụng Compose, hãy dùng lệnh gọi lại này để thiết lập thành phần kết hợp lưu trữ bằng setContent, như minh hoạ dưới đây:

class MyActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text(text = stringResource(id = R.string.greeting))
        }
    }
}

Khi onCreate hoàn tất, lệnh gọi lại tiếp theo luôn là onStart.

onStart

Khi onCreate thoát, hoạt động sẽ chuyển sang trạng thái Đã bắt đầu và người dùng có thể nhìn thấy hoạt động. Lệnh gọi lại này chứa những gì cần thiết cho các bước chuẩn bị cuối cùng của hoạt động để chuyển lên nền trước và trở nên có tính tương tác.

onResume

Hệ thống sẽ gọi lệnh gọi lại này ngay trước khi hoạt động bắt đầu tương tác với người dùng. Tại thời điểm này, activity nằm ở đầu ngăn xếp activity và ghi lại mọi hoạt động đầu vào của người dùng. Hầu hết chức năng cốt lõi của ứng dụng đều được triển khai trong phương thức onResume.

Lệnh gọi lại onPause luôn tuân theo onResume.

onPause

Hệ thống gọi onPause khi hoạt động mất tiêu điểm và chuyển sang trạng thái Tạm dừng. Trạng thái này xảy ra khi người dùng nhấn vào nút Quay lại hoặc Gần đây. Khi hệ thống gọi onPause cho hoạt động của bạn, về mặt kỹ thuật, điều này có nghĩa là hoạt động của bạn vẫn hiển thị một phần, nhưng thường là dấu hiệu cho thấy người dùng đang rời khỏi hoạt động và hoạt động sẽ sớm chuyển sang trạng thái Dừng hoặc Tiếp tục.

Một hoạt động ở trạng thái Tạm dừng có thể tiếp tục cập nhật giao diện người dùng nếu người dùng đang mong đợi giao diện người dùng cập nhật. Ví dụ về hoạt động như vậy bao gồm hoạt động cho thấy màn hình bản đồ chỉ đường hoặc trình phát đa phương tiện đang phát. Ngay cả khi những hoạt động như vậy mất tiêu điểm, người dùng vẫn muốn giao diện người dùng của họ tiếp tục cập nhật.

Bạn không nên dùng onPause để lưu dữ liệu ứng dụng hoặc dữ liệu người dùng, thực hiện các lệnh gọi mạng hoặc thực thi các giao dịch cơ sở dữ liệu. Để biết thông tin về cách lưu dữ liệu, hãy xem bài viết Lưu và khôi phục trạng thái giao diện người dùng tạm thời.

Sau khi onPause hoàn tất quá trình thực thi, lệnh gọi lại tiếp theo sẽ là onStop hoặc onResume, tuỳ thuộc vào những gì xảy ra sau khi hoạt động chuyển sang trạng thái Đã tạm dừng.

onStop

Hệ thống gọi onStop khi hoạt động không còn hiển thị với người dùng. Điều này có thể xảy ra vì hoạt động đang bị huỷ, một hoạt động mới đang bắt đầu hoặc một hoạt động hiện có đang chuyển sang trạng thái Đã tiếp tục và đang che phủ hoạt động đã dừng. Trong tất cả những trường hợp này, hoạt động đã dừng sẽ không còn xuất hiện nữa.

Lệnh gọi lại tiếp theo mà hệ thống gọi là onRestart, nếu hoạt động quay lại tương tác với người dùng, hoặc onDestroy nếu hoạt động này hoàn toàn kết thúc.

onRestart

Hệ thống gọi lệnh gọi lại này khi một hoạt động ở trạng thái Dừng sắp khởi động lại. onRestart khôi phục trạng thái của hoạt động từ thời điểm hoạt động đó bị dừng.

Lệnh gọi lại này luôn đi kèm với onStart.

onDestroy

Hệ thống sẽ gọi lệnh gọi lại này trước khi một hoạt động bị huỷ.

Lệnh gọi lại này là lệnh gọi lại cuối cùng mà hoạt động nhận được. onDestroy thường được triển khai để đảm bảo rằng tất cả tài nguyên của một hoạt động đều được giải phóng khi hoạt động hoặc quy trình chứa hoạt động đó bị huỷ.

Phần này chỉ giới thiệu về chủ đề này. Để biết thông tin chi tiết hơn về vòng đời của activity và các lệnh gọi lại của vòng đời này, hãy xem phần Vòng đời hoạt động.