Chu kỳ hoạt động

Khi người dùng di chuyển qua, ra khỏi và quay lại ứng dụng, các thực thể Activity trong ứng dụng sẽ chuyển đổi qua nhiều trạng thái trong vòng đời của chúng. Lớp Activity cung cấp một số lệnh gọi lại cho hoạt động biết khi nào một trạng thái thay đổi hoặc hệ thống đang tạo, dừng hoặc tiếp tục một hoạt động hoặc huỷ bỏ quy trình chứa hoạt động đó.

Trong các phương thức gọi lại trong vòng đời, bạn có thể khai báo cách hoạt động của bạn hoạt động khi người dùng rời khỏi và vào lại hoạt động. Ví dụ: nếu đang tạo một trình phát video phát trực tuyến, bạn có thể tạm dừng video và chấm dứt kết nối mạng khi người dùng chuyển sang một ứng dụng khác. Khi người dùng quay lại, bạn có thể kết nối lại với mạng và cho phép người dùng tiếp tục xem video từ cùng một vị trí.

Mỗi lệnh gọi lại cho phép bạn thực hiện công việc cụ thể phù hợp với một sự thay đổi trạng thái nhất định. Việc thực hiện đúng công việc vào đúng thời điểm và xử lý quá trình chuyển đổi đúng cách sẽ giúp ứng dụng của bạn mạnh mẽ và hiệu suất hơn. Ví dụ: nếu triển khai tốt các phương thức gọi lại trong vòng đời, ứng dụng của bạn có thể tránh được những điều sau:

  • Sự cố khi người dùng nhận cuộc gọi điện thoại hoặc chuyển sang một ứng dụng khác trong khi dùng ứng dụng của bạn.
  • Tiêu thụ tài nguyên hệ thống có giá trị khi người dùng không chủ động sử dụng phần mềm đó.
  • Mất tiến trình của người dùng nếu họ rời khỏi ứng dụng và quay lại ứng dụng sau đó.
  • Sự cố hoặc mất tiến trình của người dùng khi màn hình xoay giữa hướng ngang và dọc.

Tài liệu này giải thích chi tiết về vòng đời hoạt động. Tài liệu này mở đầu bằng cách mô tả mô hình vòng đời. Tiếp theo, phần này giải thích từng lệnh gọi lại: những gì xảy ra nội bộ trong khi thực thi và những gì bạn cần triển khai trong các lệnh gọi lại đó.

Sau đó, bài viết này giới thiệu ngắn gọn mối quan hệ giữa trạng thái hoạt động và lỗ hổng bảo mật bị hệ thống loại bỏ của một quy trình. Cuối cùng, tài liệu này thảo luận một số chủ đề liên quan đến quá trình chuyển đổi giữa các trạng thái hoạt động.

Để biết thông tin về cách xử lý vòng đời, bao gồm cả hướng dẫn về các phương pháp hay nhất, hãy xem các bài viết Xử lý vòng đời bằng các thành phần nhận biết vòng đờiLưu trạng thái giao diện người dùng. Để tìm hiểu cách xây dựng một ứng dụng mạnh mẽ, đủ tiêu chuẩn phát hành công khai bằng cách sử dụng các hoạt động kết hợp với thành phần cấu trúc, hãy xem Hướng dẫn về cấu trúc ứng dụng.

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

Để điều hướng quá trình chuyển đổi giữa các giai đoạn trong vòng đời hoạt động, lớp Activity cung cấp một tập hợp cốt lõi gồm 6 lệnh gọi lại: onCreate(), onStart(), onResume(), onPause(), onStop()onDestroy(). Hệ thống sẽ gọi từng lệnh gọi lại này khi hoạt động chuyển sang trạng thái mới.

Hình 1 trình bày trực quan mô hình này.

Hình 1. Hình minh hoạ đơn giản về vòng đời hoạt động.

Khi người dùng bắt đầu rời khỏi hoạt động, hệ thống sẽ gọi các phương thức để huỷ bỏ hoạt động. Trong một số trường hợp, hoạt động chỉ bị huỷ một phần và vẫn nằm trong bộ nhớ, chẳng hạn như khi người dùng chuyển sang một ứng dụng khác. Trong những trường hợp như vậy, hoạt động vẫn có thể quay lại nền trước.

Nếu người dùng quay lại hoạt động, hoạt động đó sẽ tiếp tục từ nơi người dùng đã dừng lại. Với một vài ngoại lệ, ứng dụng sẽ bị hạn chế bắt đầu hoạt động khi chạy ở chế độ nền.

Khả năng hệ thống tắt một quy trình nhất định, cùng với các hoạt động trong đó, phụ thuộc vào trạng thái của hoạt động tại thời điểm đó. Để biết thêm thông tin về mối quan hệ giữa trạng thái và lỗ hổng bị đẩy, hãy xem phần trạng thái hoạt động và việc bị đẩy ra khỏi bộ nhớ.

Tuỳ thuộc vào mức độ phức tạp của hoạt động, có thể bạn không cần triển khai tất cả các phương thức vòng đời. Tuy nhiên, điều quan trọng là bạn phải hiểu rõ từng chỉ báo và triển khai những yếu tố giúp ứng dụng của bạn hoạt động theo cách mà người dùng mong đợi.

Phương thức gọi lại trong vòng đời

Phần này cung cấp thông tin về khái niệm và cách triển khai các phương thức gọi lại được dùng trong vòng đời hoạt động.

Một số thao tác thuộc về các phương thức của vòng đời hoạt động. Tuy nhiên, mã vị trí triển khai các thao tác của một thành phần phụ thuộc trong thành phần đó, thay vì phương thức vòng đời hoạt động. Để đạt được điều này, bạn cần làm cho thành phần phụ thuộc nhận biết được vòng đời. Để tìm hiểu cách làm cho các thành phần phụ thuộc nhận biết được vòng đời, hãy xem bài viết Xử lý vòng đời bằng các thành phần nhận biết vòng đời.

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 lần đầu tiên. Khi tạo hoạt động, hoạt động sẽ chuyển sang trạng thái Đã tạo. Trong phương thức onCreate(), thực hiện logic khởi động ứng dụng cơ bản chỉ xảy ra một lần trong toàn bộ thời gian hoạt động.

Ví dụ: việc triển khai onCreate() của bạn có thể liên kết dữ liệu với danh sách, liên kết hoạt động với ViewModel và tạo thực thể cho một số biến trong phạm vi lớp. Phương thức này nhận được tham số savedInstanceState. Đây là một đối tượng Bundle chứa trạng thái đã lưu trước đó của hoạt động. Nếu hoạt động chưa từng tồn tại trước đó, thì giá trị của đối tượng Bundle sẽ là rỗng.

Nếu bạn có một thành phần nhận biết được vòng đời được kết nối với vòng đời của hoạt động, thì thành phần đó sẽ nhận được sự kiện ON_CREATE. Phương thức chú giải bằng @OnLifecycleEvent được gọi để thành phần nhận biết vòng đời có thể thực hiện bất kỳ mã thiết lập nào cần thiết cho trạng thái đã tạo.

Ví dụ sau về phương thức onCreate() cho thấy cách thiết lập cơ bản cho hoạt động, chẳng hạn như khai báo giao diện người dùng (được xác định trong tệp bố cục XML), xác định các biến thành phần và định cấu hình một số giao diện người dùng. Trong ví dụ này, tệp bố cục XML sẽ chuyển mã nhận dạng tài nguyên R.layout.main_activity của tệp sang setContentView().

Kotlin

lateinit var textView: TextView

// Some transient state for the activity instance.
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState)

    // Recover the instance state.
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity)

    // Initialize member TextView so it is available later.
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState)
}

Java

TextView textView;

// Some transient state for the activity instance.
String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState);

    // Recover the instance state.
    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity);

    // Initialize member TextView so it is available later.
    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState);
}

Thay vì xác định tệp XML và chuyển tệp đó vào setContentView(), bạn có thể tạo đối tượng View mới trong mã hoạt động và xây dựng hệ phân cấp khung hiển thị bằng cách chèn đối tượng View mới vào ViewGroup. Sau đó, bạn sử dụng bố cục đó bằng cách truyền ViewGroup gốc đến setContentView(). Để biết thêm thông tin về cách tạo giao diện người dùng, vui lòng xem tài liệu về giao diện người dùng.

Hoạt động của bạn không duy trì ở trạng thái Đã tạo. Sau khi phương thức onCreate() hoàn tất quá trình thực thi, hoạt động sẽ chuyển sang trạng thái Started (Đã bắt đầu) và hệ thống sẽ gọi phương thức onStart()onResume() liên tiếp.

onStart()

Khi hoạt động chuyển sang trạng thái Started (Đã khởi động), hệ thống sẽ gọi onStart(). Lệnh gọi này giúp người dùng nhìn thấy hoạt động khi ứng dụng chuẩn bị cho hoạt động xâm nhập vào nền trước và có tính tương tác. Ví dụ: phương thức này là nơi mã duy trì giao diện người dùng được khởi động.

Khi hoạt động chuyển sang trạng thái Started (Đã khởi động), mọi thành phần nhận biết được vòng đời gắn liền với vòng đời của hoạt động sẽ nhận được sự kiện ON_START.

Phương thức onStart() hoàn tất nhanh chóng và cũng giống như trạng thái Đã tạo, hoạt động không duy trì ở trạng thái Đã bắt đầu. Sau khi lệnh gọi lại này kết thúc, hoạt động sẽ chuyển sang trạng thái Tiếp tục và hệ thống sẽ gọi phương thức onResume().

onResume()

Khi hoạt động chuyển sang trạng thái Tiếp tục, hoạt động sẽ xuất hiện ở nền trước và hệ thống sẽ gọi lệnh gọi lại onResume(). Đây là trạng thái mà ứng dụng tương tác với người dùng. Ứng dụng vẫn ở trạng thái này cho đến khi có điều gì đó xảy ra để tách khỏi ứng dụng, chẳng hạn như thiết bị nhận cuộc gọi điện thoại, người dùng chuyển đến một hoạt động khác hoặc màn hình thiết bị tắt.

Khi hoạt động chuyển sang trạng thái Tiếp tục, mọi thành phần nhận biết được vòng đời liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_RESUME. Đây là nơi các thành phần trong vòng đời có thể bật bất kỳ chức năng nào cần chạy trong khi các thành phần đó đang hiển thị và ở nền trước, chẳng hạn như khởi động bản xem trước của máy ảnh.

Khi một sự kiện gây gián đoạn xảy ra, hoạt động sẽ chuyển sang trạng thái Paused và hệ thống sẽ gọi lệnh gọi lại onPause().

Nếu hoạt động trả về trạng thái Tiếp tục từ trạng thái Đã tạm dừng, thì hệ thống một lần nữa sẽ gọi phương thức onResume(). Vì lý do này, hãy triển khai onResume() để khởi chạy các thành phần mà bạn phát hành trong onPause() và để thực hiện mọi quá trình khởi chạy khác phải xảy ra mỗi khi hoạt động chuyển sang trạng thái Tiếp tục.

Dưới đây là ví dụ về một thành phần nhận biết được vòng đời sẽ truy cập vào máy ảnh khi thành phần này nhận được sự kiện ON_RESUME:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

Java

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }
    ...
}

Mã ở trên khởi chạy máy ảnh sau khi LifecycleObserver nhận được sự kiện ON_RESUME. Tuy nhiên, ở chế độ nhiều cửa sổ, hoạt động của bạn có thể hiển thị đầy đủ ngay cả khi ở trạng thái Đã tạm dừng. Ví dụ: khi ứng dụng ở chế độ nhiều cửa sổ và người dùng nhấn vào cửa sổ không chứa hoạt động, hoạt động sẽ chuyển sang trạng thái Đã tạm dừng.

Nếu bạn chỉ muốn máy ảnh hoạt động khi ứng dụng được tiếp tục (hiển thị và hoạt động ở nền trước), hãy khởi chạy máy ảnh sau sự kiện ON_RESUME được minh hoạ trước đó. Nếu bạn muốn giữ máy ảnh hoạt động trong khi hoạt động bị Tạm dừng nhưng hiển thị, chẳng hạn như ở chế độ nhiều cửa sổ, hãy khởi động máy ảnh sau sự kiện ON_START.

Tuy nhiên, việc máy ảnh hoạt động trong khi hoạt động bị Tạm dừng có thể từ chối quyền truy cập vào máy ảnh vào một ứng dụng Tiếp tục khác ở chế độ nhiều cửa sổ. Đôi khi, bạn cần phải giữ cho máy ảnh hoạt động trong khi hoạt động bị Tạm dừng, nhưng điều này có thể thực sự làm giảm chất lượng trải nghiệm tổng thể của người dùng nếu bạn làm như vậy.

Vì lý do này, hãy suy nghĩ kỹ về vị trí thích hợp nhất trong vòng đời để kiểm soát tài nguyên hệ thống dùng chung trong bối cảnh của chế độ nhiều cửa sổ. Để tìm hiểu thêm về cách hỗ trợ chế độ nhiều cửa sổ, hãy xem bài viết Hỗ trợ nhiều cửa sổ.

Bất kể bạn chọn sự kiện tích hợp nào để thực hiện thao tác khởi chạy, hãy nhớ sử dụng sự kiện trong vòng đời tương ứng để giải phóng tài nguyên. Nếu bạn khởi tạo một nội dung nào đó sau sự kiện ON_START, hãy huỷ bỏ hoặc chấm dứt nội dung đó sau sự kiện ON_STOP. Nếu bạn khởi chạy sau sự kiện ON_RESUME, hãy giải phóng sau sự kiện ON_PAUSE.

Đoạn mã trên đặt mã khởi chạy máy ảnh trong một thành phần nhận biết được vòng đời. Thay vào đó, bạn có thể trực tiếp đặt mã này vào các phương thức gọi lại trong vòng đời hoạt động, chẳng hạn như onStart()onStop(). Tuy nhiên, bạn không nên thực hiện thao tác này. Việc thêm logic này vào một thành phần độc lập, nhận biết được vòng đời cho phép bạn sử dụng lại thành phần đó trên nhiều hoạt động mà không phải sao chép mã. Để tìm hiểu cách tạo một thành phần nhận biết được vòng đời, hãy xem bài viết Xử lý vòng đời bằng các thành phần nhận biết vòng đời.

onPause()

Hệ thống gọi phương thức này là chỉ báo đầu tiên cho biết người dùng sẽ rời khỏi hoạt động của bạn, mặc dù không phải lúc nào cũng có nghĩa là hoạt động đang bị huỷ. Thuộc tính này cho biết hoạt động không còn ở nền trước nhưng vẫn hiển thị nếu người dùng ở chế độ nhiều cửa sổ. Có một số lý do khiến một hoạt động có thể chuyển sang trạng thái này:

  • Một sự kiện làm gián đoạn quá trình thực thi ứng dụng, như mô tả trong phần về lệnh gọi lại onResume(), sẽ tạm dừng hoạt động hiện tại. Đây là trường hợp phổ biến nhất.
  • Ở chế độ nhiều cửa sổ, tại bất cứ thời điểm nào chỉ một ứng dụng được lấy tiêu điểm và hệ thống sẽ tạm dừng tất cả các ứng dụng khác.
  • Việc mở một hoạt động mới, nửa trong suốt (chẳng hạn như hộp thoại) sẽ tạm dừng hoạt động có trong đó. Miễn là hoạt động chỉ xuất hiện một phần nhưng không được đặt tiêu điểm, hoạt động đó sẽ vẫn tạm dừng.

Khi một hoạt động chuyển sang trạng thái Paused (Đã tạm dừng), mọi thành phần nhận biết được vòng đời liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_PAUSE. Đây là nơi các thành phần trong vòng đời có thể dừng bất kỳ chức năng nào không cần chạy trong khi thành phần không chạy ở nền trước, chẳng hạn như dừng bản xem trước của máy ảnh.

Hãy sử dụng phương thức onPause() để tạm dừng hoặc điều chỉnh những hoạt động không thể tiếp tục hoặc có thể tiếp tục ở trạng thái kiểm duyệt, trong khi Activity đang ở trạng thái Paused (Đã tạm dừng) và bạn dự kiến sẽ sớm tiếp tục hoạt động đó.

Bạn cũng có thể sử dụng phương thức onPause() để giải phóng tài nguyên hệ thống, tay cầm đến cảm biến (như GPS) hoặc bất kỳ tài nguyên nào ảnh hưởng đến thời lượng pin trong khi hoạt động của bạn bị Tạm dừng và người dùng không cần đến chúng.

Tuy nhiên, như đã đề cập trong phần về onResume(), hoạt động Paused (Đã tạm dừng) vẫn có thể hiển thị đầy đủ nếu ứng dụng ở chế độ nhiều cửa sổ. Hãy cân nhắc sử dụng onStop() thay vì onPause() để phát hành hoặc điều chỉnh đầy đủ các tài nguyên và hoạt động liên quan đến giao diện người dùng, nhằm hỗ trợ tốt hơn cho chế độ nhiều cửa sổ.

Ví dụ sau đây về một LifecycleObserver phản ứng với sự kiện ON_PAUSE là phiên bản tương ứng với ví dụ về sự kiện ON_RESUME trước đó, giải phóng máy ảnh khởi chạy sau khi nhận được sự kiện ON_RESUME:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

Java

public class JavaCameraComponent implements LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }
    ...
}

Ví dụ này đặt mã phát hành máy ảnh sau khi LifecycleObserver nhận được sự kiện ON_PAUSE.

Quá trình thực thi onPause() rất ngắn gọn và không nhất thiết phải cung cấp đủ thời gian để thực hiện các thao tác lưu. Vì lý do này, không sử dụng onPause() để lưu dữ liệu người dùng hoặc ứng dụng, thực hiện lệnh gọi mạng hoặc thực thi các giao dịch cơ sở dữ liệu. Công việc như vậy có thể không hoàn tất trước khi phương thức này hoàn tất.

Thay vào đó, hãy thực hiện các thao tác tắt tải nặng trong onStop(). Để biết thêm thông tin về các thao tác phù hợp cần thực hiện trong onStop(), hãy xem phần tiếp theo. Để biết thêm thông tin về cách lưu dữ liệu, hãy xem phần lưu và khôi phục trạng thái.

Việc hoàn tất phương thức onPause() không có nghĩa là hoạt động rời khỏi trạng thái Paused (Đã tạm dừng). Thay vào đó, hoạt động vẫn ở trạng thái này cho đến khi hoạt động tiếp tục hoặc người dùng hoàn toàn không nhìn thấy hoạt động đó. Nếu hoạt động tiếp tục, hệ thống một lần nữa gọi lệnh gọi lại onResume().

Nếu hoạt động trả từ trạng thái Paused (Đã tạm dừng) sang trạng thái Tiếp tục (Tiếp tục), thì hệ thống sẽ giữ thực thể Activity nằm trong bộ nhớ và gọi lại thực thể đó khi hệ thống gọi onResume(). Trong trường hợp này, bạn không cần khởi động lại các thành phần được tạo trong bất kỳ phương thức gọi lại nào dẫn đến trạng thái Tiếp tục. Nếu hoạt động bị ẩn hoàn toàn, hệ thống sẽ gọi onStop().

onStop()

Khi người dùng không còn thấy hoạt động của bạn, hoạt động sẽ chuyển sang trạng thái Đã dừng và hệ thống sẽ thực hiện lệnh gọi lại onStop(). Điều này có thể xảy ra khi một hoạt động mới khởi chạy che phủ toàn bộ màn hình. Hệ thống cũng gọi onStop() khi hoạt động chạy xong và sắp bị chấm dứt.

Khi hoạt động chuyển sang trạng thái Đã dừng, mọi thành phần nhận biết được vòng đời gắn liền với vòng đời của hoạt động sẽ nhận được sự kiện ON_STOP. Đây là nơi các thành phần trong vòng đời có thể dừng bất kỳ chức năng nào không cần chạy trong khi thành phần không hiển thị trên màn hình.

Trong phương thức onStop(), hãy huỷ bỏ hoặc điều chỉnh các tài nguyên không cần thiết trong khi ứng dụng không hiển thị với người dùng. Ví dụ: ứng dụng của bạn có thể tạm dừng ảnh động hoặc chuyển từ thông tin cập nhật vị trí chi tiết sang chi tiết tương đối. Việc sử dụng onStop() thay vì onPause() có nghĩa là công việc liên quan đến giao diện người dùng sẽ tiếp tục, ngay cả khi người dùng đang xem hoạt động của bạn ở chế độ nhiều cửa sổ.

Ngoài ra, hãy sử dụng onStop() để thực hiện các thao tác tắt tương đối tiêu tốn nhiều CPU. Ví dụ: nếu không tìm được thời điểm thích hợp hơn để lưu thông tin vào cơ sở dữ liệu, bạn có thể thực hiện việc này trong onStop(). Ví dụ sau đây minh hoạ cách triển khai onStop() giúp lưu nội dung của ghi chú nháp vào bộ nhớ ổn định:

Kotlin

override fun onStop() {
    // Call the superclass method first.
    super.onStop()

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

Java

@Override
protected void onStop() {
    // Call the superclass method first.
    super.onStop();

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

Mã mẫu ở trên sử dụng trực tiếp SQLite. Tuy nhiên, bạn nên sử dụng Room, một thư viện cố định cung cấp một lớp trừu tượng trên SQLite. Để tìm hiểu thêm về các lợi ích khi sử dụng Room và cách triển khai Room trong ứng dụng của bạn, hãy xem hướng dẫn Thư viện lưu trữ Room.

Khi hoạt động chuyển sang trạng thái Paused (Đã dừng), đối tượng Activity sẽ được lưu giữ trong bộ nhớ: đối tượng này duy trì tất cả thông tin trạng thái và thành viên, nhưng không được đính kèm vào trình quản lý cửa sổ. Khi tiếp tục, hoạt động sẽ ghi nhớ thông tin này.

Bạn không cần khởi động lại các thành phần được tạo trong bất kỳ phương thức gọi lại nào dẫn đến trạng thái Tiếp tục. Hệ thống cũng theo dõi trạng thái hiện tại cho mỗi đối tượng View trong bố cục. Vì vậy, nếu người dùng nhập văn bản vào tiện ích EditText, thì nội dung đó sẽ được giữ lại nên bạn không cần lưu và khôi phục nội dung đó.

Lưu ý: Sau khi hoạt động của bạn bị dừng, hệ thống có thể huỷ bỏ quy trình chứa hoạt động đó nếu cần khôi phục bộ nhớ. Ngay cả khi huỷ bỏ quá trình trong khi hoạt động bị dừng, hệ thống vẫn giữ nguyên trạng thái của các đối tượng View, chẳng hạn như văn bản trong tiện ích EditText, trong Bundle (một blob của các cặp khoá-giá trị) và khôi phục các đối tượng đó nếu người dùng quay lại hoạt động. Để biết thêm thông tin về cách khôi phục một hoạt động mà người dùng trả về, hãy xem phần lưu và khôi phục trạng thái.

Từ trạng thái Đã dừng, hoạt động sẽ quay lại để tương tác với người dùng hoặc hoạt động đã chạy xong và biến mất. Nếu hoạt động xuất hiện trở lại, hệ thống sẽ gọi onRestart(). Nếu Activity chạy xong, hệ thống sẽ gọi onDestroy().

onDestroy()

onDestroy() được gọi trước khi huỷ hoạt động. Hệ thống gọi lệnh gọi lại này vì một trong hai lý do sau:

  1. Hoạt động đang kết thúc, do người dùng đóng hoàn toàn hoạt động hoặc do finish() được gọi trên hoạt động.
  2. Hệ thống đang tạm thời huỷ bỏ hoạt động do có sự thay đổi về cấu hình, chẳng hạn như việc xoay thiết bị hoặc chuyển sang chế độ nhiều cửa sổ.

Khi hoạt động chuyển sang trạng thái đã bị huỷ bỏ, mọi thành phần nhận biết được vòng đời liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_DESTROY. Đây là nơi các thành phần vòng đời có thể dọn dẹp mọi thứ cần thiết trước khi Activity bị huỷ.

Thay vì đưa logic vào Activity để xác định lý do tại sao nó bị huỷ, hãy sử dụng đối tượng ViewModel để chứa dữ liệu chế độ xem liên quan cho Activity của bạn. Nếu Activity được tạo lại do thay đổi về cấu hình, thì ViewModel không phải làm gì vì nó được giữ nguyên và cấp cho thực thể Activity tiếp theo.

Nếu Activity không được tạo lại thì ViewModel sẽ được gọi phương thức onCleared(). Phương thức này có thể xoá mọi dữ liệu cần thiết trước khi bị huỷ. Bạn có thể phân biệt giữa hai trường hợp này bằng phương thức isFinishing().

Nếu hoạt động đang kết thúc, onDestroy() sẽ là lệnh gọi lại trong vòng đời cuối cùng mà hoạt động nhận được. Nếu onDestroy() được gọi do thay đổi cấu hình, hệ thống sẽ ngay lập tức tạo một thực thể hoạt động mới, sau đó gọi onCreate() trên thực thể mới đó trong cấu hình mới.

Lệnh gọi lại onDestroy() sẽ huỷ bỏ mọi tài nguyên chưa được các lệnh gọi lại trước đó huỷ phát, chẳng hạn như onStop().

Trạng thái hoạt động và đẩy ra khỏi bộ nhớ

Hệ thống sẽ loại bỏ các quy trình khi cần giải phóng RAM. Khả năng hệ thống tắt một quy trình nhất định phụ thuộc vào trạng thái của quy trình tại thời điểm đó. Trạng thái của quy trình sẽ phụ thuộc vào trạng thái của hoạt động đang chạy trong quy trình đó. Bảng 1 cho thấy mối tương quan giữa trạng thái của quy trình, trạng thái hoạt động và khả năng hệ thống buộc tắt quy trình. Bảng này chỉ áp dụng nếu một quy trình không chạy các loại thành phần ứng dụng khác.

Khả năng bị giết Trạng thái xử lý Trạng thái hoạt động cuối cùng
Thấp nhất Nền trước (có hoặc sắp được lấy tiêu điểm) Đã tiếp tục
Thấp Hiển thị (không có tiêu điểm) Đã bắt đầu/Tạm dừng
Cao hơn Nền (ẩn) Stopped (Đã dừng)
Cao nhất Trống Đã huỷ bỏ

Bảng 1. Mối quan hệ giữa vòng đời của quy trình và trạng thái hoạt động.

Hệ thống không bao giờ trực tiếp loại bỏ một hoạt động để giải phóng bộ nhớ. Thay vào đó, nó sẽ dừng quy trình mà hoạt động chạy, huỷ bỏ không chỉ hoạt động mà còn huỷ mọi thứ khác đang chạy trong quy trình đó. Để tìm hiểu cách lưu giữ và khôi phục trạng thái giao diện người dùng của hoạt động khi quá trình bị buộc tắt do hệ thống gây ra, hãy xem phần về lưu và khôi phục trạng thái.

Người dùng cũng có thể loại bỏ một quy trình bằng cách sử dụng Trình quản lý ứng dụng trong phần Cài đặt để loại bỏ ứng dụng tương ứng.

Để biết thêm thông tin về các quy trình, hãy xem bài viết Tổng quan về quy trình và luồng.

Lưu và khôi phục trạng thái tạm thời của giao diện người dùng

Người dùng muốn trạng thái giao diện người dùng của một hoạt động vẫn giữ nguyên trong suốt quá trình thay đổi cấu hình, chẳng hạn như khi thực hiện thao tác xoay hoặc khi chuyển sang chế độ nhiều cửa sổ. Tuy nhiên, theo mặc định, hệ thống sẽ huỷ hoạt động khi xảy ra thay đổi về cấu hình như vậy, xoá sạch mọi trạng thái giao diện người dùng đã lưu trong thực thể của hoạt động đó.

Tương tự, người dùng mong muốn trạng thái giao diện người dùng vẫn giữ nguyên nếu họ tạm thời chuyển từ ứng dụng của bạn sang một ứng dụng khác và sau đó quay lại ứng dụng của bạn. Tuy nhiên, hệ thống có thể huỷ bỏ quy trình của ứng dụng trong khi người dùng vắng mặt và hoạt động của bạn bị dừng.

Khi các quy tắc ràng buộc của hệ thống huỷ bỏ hoạt động, hãy duy trì trạng thái giao diện người dùng tạm thời của người dùng bằng cách sử dụng kết hợp ViewModel, onSaveInstanceState() và/hoặc bộ nhớ cục bộ. Để tìm hiểu thêm về kỳ vọng của người dùng so với hành vi của hệ thống, cũng như cách duy trì tốt nhất dữ liệu trạng thái giao diện người dùng phức tạp trong quá trình bị buộc tắt và hoạt động do hệ thống gây ra, hãy xem bài viết Lưu trạng thái giao diện người dùng.

Phần này trình bày về trạng thái thực thể và cách triển khai phương thức onSaveInstance(), đây là lệnh gọi lại trên chính hoạt động đó. Nếu dữ liệu giao diện người dùng nhẹ, bạn có thể sử dụng riêng onSaveInstance() để duy trì trạng thái giao diện người dùng trong cả các thay đổi về cấu hình và trường hợp bị buộc tắt do hệ thống gây ra. Tuy nhiên, vì onSaveInstance() phát sinh chi phí chuyển đổi tuần tự/huỷ chuyển đổi tuần tự, nên trong hầu hết các trường hợp, bạn sử dụng cả ViewModelonSaveInstance(), như đã nêu trong phần Lưu trạng thái giao diện người dùng.

Lưu ý: Để tìm hiểu thêm về các thay đổi về cấu hình, cách hạn chế việc tạo lại Hoạt động nếu cần, cũng như cách phản ứng với những thay đổi về cấu hình đó từ hệ thống Khung hiển thị và Jetpack Compose, hãy xem trang Xử lý các thay đổi về cấu hình.

Trạng thái của thực thể

Có một vài trường hợp hoạt động bị huỷ bỏ do hành vi thông thường của ứng dụng, chẳng hạn như khi người dùng nhấn nút Quay lại hoặc hoạt động báo hiệu hoạt động đó bị huỷ bằng cách gọi phương thức finish().

Khi hoạt động bị huỷ bỏ do người dùng nhấn vào Quay lại hoặc hoạt động tự kết thúc, thì cả khái niệm của người dùng và hệ thống về thực thể Activity đó sẽ biến mất vĩnh viễn. Trong các trường hợp này, kỳ vọng của người dùng khớp với hành vi của hệ thống và bạn không cần làm gì thêm.

Tuy nhiên, nếu hệ thống huỷ bỏ hoạt động do các điều kiện ràng buộc của hệ thống (chẳng hạn như thay đổi cấu hình hoặc áp lực về bộ nhớ), thì mặc dù thực thể Activity thực tế đã biến mất, nhưng hệ thống sẽ nhớ rằng thực thể đó đã tồn tại. Nếu người dùng cố gắng quay lại hoạt động, hệ thống sẽ tạo một thực thể mới của hoạt động đó bằng cách sử dụng tập dữ liệu đã lưu mô tả trạng thái của hoạt động khi hoạt động bị huỷ.

Dữ liệu đã lưu mà hệ thống sử dụng để khôi phục trạng thái trước đó được gọi là trạng thái thực thể. Đây là một tập hợp các cặp khoá-giá trị được lưu trữ trong đối tượng Bundle. Theo mặc định, hệ thống sử dụng trạng thái thực thể Bundle để lưu thông tin về từng đối tượng View trong bố cục hoạt động của bạn, chẳng hạn như giá trị văn bản đã nhập vào tiện ích EditText.

Vì vậy, nếu thực thể hoạt động của bạn bị huỷ bỏ và tạo lại, trạng thái của bố cục sẽ được khôi phục về trạng thái trước đó mà không cần bạn nhập mã. Tuy nhiên, hoạt động của bạn có thể có thêm thông tin trạng thái mà bạn muốn khôi phục, chẳng hạn như các biến thành phần theo dõi tiến trình của người dùng trong hoạt động.

Lưu ý: Để hệ thống Android khôi phục trạng thái của các khung hiển thị trong hoạt động, mỗi khung hiển thị phải có một mã nhận dạng duy nhất do thuộc tính android:id cung cấp.

Đối tượng Bundle không phù hợp để duy trì nhiều hơn một lượng dữ liệu nhỏ, vì đối tượng này đòi hỏi phải chuyển đổi tuần tự trên luồng chính và sử dụng bộ nhớ cho quy trình hệ thống. Để lưu giữ nhiều hơn một lượng dữ liệu rất nhỏ, hãy thực hiện phương pháp kết hợp để bảo toàn dữ liệu, sử dụng bộ nhớ cục bộ ổn định, phương thức onSaveInstanceState() và lớp ViewModel, như đã nêu trong bài viết Lưu trạng thái giao diện người dùng.

Lưu trạng thái giao diện người dùng đơn giản, gọn nhẹ bằng onSaveInstanceState()

Khi hoạt động của bạn bắt đầu dừng lại, hệ thống sẽ gọi phương thức onSaveInstanceState() để hoạt động của bạn có thể lưu thông tin trạng thái vào một gói trạng thái của thực thể. Cách triển khai mặc định của phương thức này sẽ lưu thông tin tạm thời về trạng thái của hệ phân cấp khung hiển thị của hoạt động, chẳng hạn như văn bản trong tiện ích EditText hoặc vị trí cuộn của tiện ích ListView.

Để lưu thêm thông tin về trạng thái thực thể cho hoạt động của bạn, hãy ghi đè onSaveInstanceState() và thêm cặp khoá-giá trị vào đối tượng Bundle đã được lưu trong trường hợp hoạt động của bạn bị huỷ đột ngột. Khi ghi đè onSaveInstanceState(), bạn cần gọi phương thức triển khai lớp cấp cao nếu bạn muốn phương thức triển khai mặc định lưu trạng thái của hệ phân cấp khung hiển thị. Lệnh này được minh hoạ trong ví dụ sau:

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game state.
    outState?.run {
        putInt(STATE_SCORE, currentScore)
        putInt(STATE_LEVEL, currentLevel)
    }

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(outState)
}

companion object {
    val STATE_SCORE = "playerScore"
    val STATE_LEVEL = "playerLevel"
}

Java

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state.
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(savedInstanceState);
}

Lưu ý: onSaveInstanceState() không được gọi khi người dùng đóng hoạt động một cách rõ ràng hoặc trong các trường hợp khác khi finish() được gọi.

Để lưu dữ liệu cố định, chẳng hạn như lựa chọn ưu tiên của người dùng hoặc dữ liệu cho cơ sở dữ liệu, hãy áp dụng các cơ hội thích hợp khi hoạt động của bạn chạy ở nền trước. Nếu không có cơ hội như vậy, hãy lưu dữ liệu liên tục trong phương thức onStop().

Khôi phục trạng thái giao diện người dùng của hoạt động bằng trạng thái thực thể đã lưu

Khi hoạt động được tạo lại sau khi hoạt động bị huỷ bỏ trước đó, bạn có thể khôi phục trạng thái thực thể đã lưu từ Bundle mà hệ thống truyền sang hoạt động của bạn. Cả hai phương thức gọi lại onCreate() onRestoreInstanceState() đều nhận được cùng một Bundle chứa thông tin về trạng thái thực thể.

Vì phương thức onCreate() được gọi để xem hệ thống đang tạo một thực thể mới cho hoạt động của bạn hay tạo lại một thực thể trước đó, nên bạn cần kiểm tra xem trạng thái Bundle có rỗng hay không trước khi bạn cố gắng đọc. Nếu giá trị này là rỗng, thì hệ thống sẽ tạo một thực thể mới của hoạt động, thay vì khôi phục một thực thể trước đó đã bị huỷ.

Đoạn mã sau đây cho bạn biết cách khôi phục một số dữ liệu trạng thái trong onCreate():

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        with(savedInstanceState) {
            // Restore value of members from saved state.
            currentScore = getInt(STATE_SCORE)
            currentLevel = getInt(STATE_LEVEL)
        }
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        // Restore value of members from saved state.
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Thay vì khôi phục trạng thái trong onCreate(), bạn có thể chọn triển khai onRestoreInstanceState() mà hệ thống sẽ gọi sau phương thức onStart(). Hệ thống chỉ gọi onRestoreInstanceState() khi có một trạng thái đã lưu cần khôi phục. Vì vậy, bạn không cần kiểm tra xem Bundle có rỗng hay không.

Kotlin

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instance.
    savedInstanceState?.run {
        currentScore = getInt(STATE_SCORE)
        currentLevel = getInt(STATE_LEVEL)
    }
}

Java

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance.
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Thận trọng: Luôn gọi phương thức triển khai lớp cấp cao của onRestoreInstanceState() để phương thức triển khai mặc định có thể khôi phục trạng thái của hệ phân cấp khung hiển thị.

Di chuyển giữa các hoạt động

Một ứng dụng có thể vào và thoát khỏi một hoạt động (có thể nhiều lần) trong suốt thời gian hoạt động của ứng dụng, chẳng hạn như khi người dùng nhấn vào nút Quay lại của thiết bị hoặc hoạt động đó sẽ chạy một hoạt động khác.

Phần này bao gồm các chủ đề bạn cần biết để triển khai chuyển đổi hoạt động thành công. Các chủ đề này bao gồm bắt đầu một hoạt động từ một hoạt động khác, lưu trạng thái hoạt động và khôi phục trạng thái hoạt động.

Bắt đầu một hoạt động từ một hoạt động khác

Một hoạt động thường cần bắt đầu một hoạt động khác vào thời điểm nào đó. Chẳng hạn như nhu cầu này phát sinh khi một ứng dụng cần di chuyển từ màn hình hiện tại sang màn hình mới.

Tuỳ thuộc vào việc hoạt động của bạn có muốn nhận lại kết quả từ hoạt động mới sắp bắt đầu hay không, bạn có thể bắt đầu hoạt động mới bằng phương thức startActivity() hoặc phương thức startActivityForResult(). Trong cả hai trường hợp, bạn sẽ truyền vào một đối tượng Intent.

Đối tượng Intent chỉ định hoạt động chính xác bạn muốn bắt đầu hoặc mô tả loại hành động bạn muốn thực hiện. Hệ thống sẽ chọn hoạt động phù hợp cho bạn, thậm chí có thể là từ một ứng dụng khác. Đối tượng Intent cũng có thể mang một lượng nhỏ dữ liệu để sử dụng cho hoạt động được bắt đầu. Để biết thêm thông tin về lớp Intent, hãy xem bài viết Ý định và bộ lọc ý định.

startActivity()

Nếu hoạt động mới bắt đầu không cần trả về kết quả, thì hoạt động hiện tại có thể bắt đầu bằng cách gọi phương thức startActivity().

Khi làm việc trong ứng dụng của riêng mình, thông thường, bạn chỉ cần khởi chạy một hoạt động đã biết. Ví dụ: đoạn mã sau đây cho biết cách chạy một hoạt động có tên là SignInActivity.

Kotlin

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Java

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

Ứng dụng của bạn cũng có thể muốn thực hiện một số thao tác, chẳng hạn như gửi email, tin nhắn văn bản hoặc cập nhật trạng thái, bằng cách sử dụng dữ liệu từ hoạt động của bạn. Trong trường hợp này, ứng dụng có thể không có hoạt động riêng để thực hiện những thao tác như vậy. Vì vậy, bạn có thể tận dụng hoạt động do các ứng dụng khác trên thiết bị cung cấp để thực hiện những thao tác đó cho bạn.

Đây là lúc ý định thực sự có giá trị. Bạn có thể tạo một ý định mô tả hành động bạn muốn thực hiện và hệ thống sẽ khởi chạy hoạt động thích hợp từ một ứng dụng khác. Nếu có nhiều hoạt động có thể xử lý ý định, thì người dùng có thể chọn hoạt động sẽ sử dụng. Ví dụ: nếu muốn cho phép người dùng gửi email, bạn có thể tạo ý định sau:

Kotlin

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Java

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

Phần bổ sung EXTRA_EMAIL được thêm vào ý định là một mảng chuỗi địa chỉ email sẽ gửi email đến. Khi phản hồi ý định này, ứng dụng email sẽ đọc mảng chuỗi được cung cấp trong phần phụ và đặt các địa chỉ vào trường "tới" của biểu mẫu thành phần email. Trong trường hợp này, hoạt động của ứng dụng email bắt đầu và khi người dùng hoàn tất, hoạt động của bạn sẽ tiếp tục.

startActivityForResult()

Đôi khi, bạn muốn nhận lại kết quả từ một hoạt động khi hoạt động đó kết thúc. Ví dụ: bạn có thể bắt đầu một hoạt động cho phép người dùng chọn một người trong danh sách liên hệ. Khi kết thúc, phương thức này sẽ trả về người đã được chọn. Để thực hiện việc này, bạn hãy gọi phương thức startActivityForResult(Intent, int), trong đó tham số số nguyên xác định lệnh gọi.

Giá trị nhận dạng này dùng để phân biệt nhiều lệnh gọi đến startActivityForResult(Intent, int) từ cùng một hoạt động. Đây không phải là giá trị nhận dạng chung và không có nguy cơ xung đột với các ứng dụng hoặc hoạt động khác. Kết quả sẽ xuất hiện thông qua phương thức onActivityResult(int, int, Intent).

Khi một hoạt động con thoát ra, nó có thể gọi setResult(int) để trả về dữ liệu cho hoạt động gốc. Hoạt động con phải cung cấp mã kết quả. Mã này có thể là kết quả chuẩn RESULT_CANCELED, RESULT_OK hoặc bất kỳ giá trị tuỳ chỉnh nào bắt đầu từ RESULT_FIRST_USER.

Ngoài ra, hoạt động con có thể tuỳ ý trả về đối tượng Intent chứa mọi dữ liệu bổ sung mà nó muốn. Hoạt động gốc sử dụng phương thức onActivityResult(int, int, Intent), cùng với giá trị nhận dạng số nguyên mà hoạt động gốc được cung cấp ban đầu, để nhận thông tin.

Nếu một hoạt động con không thành công vì bất kỳ lý do gì, chẳng hạn như sự cố, thì hoạt động mẹ sẽ nhận được kết quả có mã RESULT_CANCELED.

Kotlin

class MyActivity : Activity() {
    // ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            // When the user center presses, let them pick a contact.
            startActivityForResult(
                    Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
                    PICK_CONTACT_REQUEST)
            return true
        }
        return false
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        when (requestCode) {
            PICK_CONTACT_REQUEST ->
                if (resultCode == RESULT_OK) {
                    // A contact was picked. Display it to the user.
                    startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
                }
        }
    }

    companion object {
        internal val PICK_CONTACT_REQUEST = 0
    }
}

Java

public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked. Display it to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

Điều phối các hoạt động

Khi một hoạt động bắt đầu một hoạt động khác, cả hai đều trải qua chuyển đổi vòng đời. Hoạt động đầu tiên ngừng hoạt động và chuyển sang trạng thái Đã tạm dừng hoặc Đã dừng, trong khi hoạt động khác được tạo. Trong trường hợp các hoạt động này chia sẻ dữ liệu được lưu vào đĩa hoặc nơi khác, bạn phải hiểu rằng hoạt động đầu tiên không bị dừng hoàn toàn trước khi tạo hoạt động thứ hai. Thay vào đó, quy trình bắt đầu quy trình thứ hai trùng lặp với quy trình dừng quy trình đầu tiên.

Thứ tự của các phương thức gọi lại trong vòng đời được xác định rõ, đặc biệt là khi hai hoạt động nằm trong cùng một quy trình (nói cách khác là cùng một ứng dụng) và một ứng dụng đang bắt đầu hoạt động kia. Dưới đây là thứ tự các thao tác xảy ra khi Hoạt động A khởi động Hoạt động B:

  1. Phương thức onPause() của hoạt động A sẽ thực thi.
  2. Các phương thức onCreate(), onStart()onResume() của Hoạt động B sẽ thực thi theo trình tự. Hoạt động B hiện tập trung vào người dùng.
  3. Nếu Hoạt động A không còn hiển thị trên màn hình, thì phương thức onStop() của hoạt động đó sẽ thực thi.

Trình tự các phương thức gọi lại trong vòng đời này cho phép bạn quản lý quá trình chuyển đổi thông tin từ hoạt động này sang hoạt động khác.