Activity Lifecycle

Activity là thành phần cơ bản trong một ứng dụng Android, trên một phần mềm truyền thống khi chạy chương trình thì các lệnh được viết trong phương thức main sẽ được gọi và thực thi, còn đối với ứng dụng Android thì thay vào đó là Activity. Một chu trình sống (lifecycle) của Activity bắt đầu bằng khởi tạo (instantiation) và kết thúc bằng hủy (destruction), trong đó có nhiều trạng thái (state) khác nhau được thay đổi luân phiên. Khi state thay đổi nó sẽ kích hoạt một sự kiện tương ứng trên Activity để lập trình viên có thể tùy chỉnh để ứng dụng thực thi một cách hiệu quả nhất.

Các trạng thái của Activity

Hệ điều hành Android can thiệp vào các Activity qua các state của nó, việc đó giúp hệ điều hành biết được Activity nào đang hoạt động, hoặc Activity nào không dùng giúp cho hệ điều hành có thể quản lý bộ nhớ và tài nguyên.

Ngoài ra các trạng thái có thể được chia làm 4 nhóm:

  1. Active/Running: Trạng thái tương ứng khi app đang ở Foreground – đang được mở trên màn hình điện thoại – hay nói cách khác là Activity đang ở trên (top) tất cả các Activity khác. Ở trạng thái này Activity được ưu tiên sử dụng bộ nhớ hoặc tài nguyên của hệ điều hành cao nhất, và chị bị hủy (kill) ở một số trường hợp bất khả kháng ví dụ yêu cầu bộ nhớ vượt quá mức của thiết bị, khi đó UI sẽ không phản hồi nữa (unresponsive)
  2. Paused: Khi thiết bị ở trạng thái nghỉ (sleep), hoặc Activity bị che bởi một Activity mới – không full-size hoặc trong suốt. Ở trạng thái này Activity vẫn còn-sống, nhưng tình trạng và các thành phần của Activity sẽ bị ngưng động và lưu lại ngay vị trí đó. Mức độ ưu tiên tài nguyên và bộ nhớ đứng thứ 2 và chị bị kill khi OS cần lấy lại tài nguyên cho các Active Activity.
  3. Stopped/Backgrounded: Activity bị chiếm hoàn toàn bởi các Activity khác, và chuyển về trạng thái Stopped hoặc bị đẩy xuống background, trạng thái này dù gọi là “stop” nhưng ứng dụng vẫn cố gắng hoạt động càng lâu càng tốt, nhưng mức độ sử dụng tài nguyên ở mức thấp nhất. Tương tự cũng có thể bị OS kill khi cần lấy lại tại nguyên cho các Activity khác.
  4. Restarted: Trạng thái này có thể có do từ Paused đến Stopped khi ứng dụng bị xóa ra khỏi bộ nhớ. Nếu người dùng quay trở về Activity thì nó sẽ được restart (khởi động lại), phục hồi các trạng thái đã được lưu và hiển thị thông tin lên UI cho người dùng.

Activity Lifecycle Methods

Android SDK và được mở rộng hơn ở Xamarin.Android framework cung cấp bộ quản lý vòng đời (lifecycle) của Activity trong ứng dụng. Khi trạng thái của Activity thay đổi thì activity sẽ được OS thông báo qua việc gọi các phương thức (methods) đặc biệt của Activiy, sau đây là sơ đồ quan hệ (thứ tự) thực thi của các phương thứ:

Nhà phát triển có thể nạp chồng (override) lại các phương thức đó để xử lý các sự kiện đó của Activiy.

OnCreate

Là phương thức đầu tiên khi activity được tạo, OnCreate mặc định sẽ được override lại trong Activity, có thể dùng để:

  • Khởi tạo View
  • Khởi tạo biến, dữ liệu
  • Nạp dữ liệu vào danh sách

Trong phương tức OnCreate có tham số Bundle, là một dictionary dùng để lưu và truyền thông tin hoặc đối tượng giữa các Activity. Nếu bundle khác null thì nghĩa là Activity đã khởi động lại (restart) và cần trả về trạng thái trước đó. Đoạn code ví dụ về việc lấy giá trị trong bundle

Lưu trữ trạng thái activity vào bundle sẽ tìm hiểu ở phần sau

Sau khi phương thức OnCreate kết thúc, Android sẽ kích hoạt phương thức OnStart

OnStart

Chạy tiếp theo phương thức OnCreate. Có thể được nạp lại (override) nếu bạn muốn chạy những tác vụ khi Activity đã hiển thị, ví dụ như refresh giá trị hiện tại trên view. Phương thức OnResume sẽ được gọi ngay sau đó.

OnResume

Phương thức được gọi khi Activity đã sẵn sàng nhận các tương tác từ phía người dùng. Activity có thể được override để thực thi một số tác vụ như:

  • Chạy các hiệu ứng chuyển động (animation)
  • Lấy dữ liệu GPS
  • Hiển thị các thông báo (alert hoặc dialog)
  • Handle các sự kiện bên ngoài

Ví dụ việc khởi tạo đối tượng để truy cập camera

OnResume khá quan trọng vì đây là phương thức duy nhất được gọi sau khi OnPause, nghĩa là các tác vụ đã được giải phóng ở OnPause phải được nạp lại tại OnResume để đảm bảo hoạt động của Activity.

OnPause

Phương thức được gọi khi Activity bị đẩy xuống background hoặc bị che khuất một phần. Activity có thể được override để thực thi một số tác vụ như:

  • Lưu trữ dữ liệu
  • Hủy hoặc giải phóng các tài nguyên
  • Hủy các handler
  • Hủy các thông báo (nếu có) bằng phương thức Dismiss()

Ví dụ về giải phóng tài nguyên camera

Có 2 trường hợp sau khi OnPause:

  1. OnResume được gọi nếu Activity trở về foreground
  2. OnStop được gọi nếu Activity tiếp tục ở background

OnStop

Phương thức được gọi khi Activity đã không còn hiển thị với người dùng, trong các trường hợp:

  • Một Activity khác đã được tạo và che hoàn toàn Activity này
  • Một activity đã tồn tại trước đó chuyển lên foreground
  • Activity bị hủy

OnStop có thể không được gọi trong trường hợp low-memory, như Android thiếu tài nguyên cho các tác vụ background. Vì vậy tốt nhất không nên dùng OnStop để nhận biết và chạy các lệnh. Phương thức tiếp theo được gọi sẽ là OnDestroy nếu activity bị hủy, hoặc OnRestart nếu activity trở lại tương tác với người dùng.

OnDetroy

Đây là phương thức cuối cùng được gọi trước khi Activity bị hủy và xóa khỏi bộ nhớ. Tình huống xấu nhất là hệ thống kill toàn bộ tiến trình của ứng dụng dẫn đến OnDestroy sẽ không được gọi. Phần lớn Activity sẽ không nạp phương thức này vì hầu như các tác vụ đã được thực thi trong OnPause và OnStop. Thường chỉ được nạp lại với các phương thức hủy các tác vụ chạy dài hạn như background task được khởi động ở OnCreate

OnRestart

Phương thức được gọi khi Activity đang stop và được mở lại. Ví dụ khi người dùng nhấn Home khi Activity trên ứng dụng đang mở, khi đó OnPause và OnStop lần lượt được gọi, Activity chuyển xuống background chứ chưa bị hủy, nếu người dùng mở lại ứng dụng qua Task Manager thì Android sẽ gọi phương OnRestart của Activity. Không có khuyến nghị nào về việc xử lý logic ở phương thức OnRestart. Bởi vì phương thức OnStart luôn được gọi bất kể là khi activity được tạo hay được khởi động lại nên các tài nguyên cần có cho ứng dụng nên được khởi tạo trong OnStart Phương thức sau OnRestart là OnStart

Back vs. Home

Phần lớn các thiết bị Android có 2 phím điều hướng là Back và Home

Có một vài khác biệt ở 2 button này, mặc dù chúng đều có thể đưa ứng dụng kèm với Activity của nó xuống background. Khi người dùng click Back button, thì Android hiểu là activity đó đã xong và sẽ hủy nó. Ngược lại, khi click Home button activity chỉ chuyển xuống background – Android sẽ không hủy activity.

Quản lý trạng thái trong ứng dụng

Khi activity stop Andoird cung cấp các cơ hội để bạn lưu trữ lại trạng thái của Activity để cho các hoạt động tái lập sau đó. Gọi chung là ” instance state”. Bạn có 3 lựa chọn để lưu trữ trạng thái:

  1. Lưu các dữ liệu chính vào Dictionary Bundle mà Android dùng để lưu trạng thái.
  2. Tạo các class để lưu lại các đối tượng phức tạp như Bitmap. Android sẽ dùng các class đó để lưu trạng thái.
  3. Thay đổi cấu hình lifecycle và tạo riêng các tác vụ để đảm bảo trạng thái ứng dụng.

“Cái số 3 không biết làm nên chỉ có hướng dẫn của 2 cái đầu”

Bundle State

Một phương pháp chính để lưu instance state theo kiểu lưu key/value vào bundle. Được nạp lại vào tham số của phương thức OnCreate khi activity được tạo, bundle có thể được dùng để phục hồi instance state. Không khuyến khích lưu trữ các loại data phức tạo (như bitmaps) vào bundle; chỉ nên lưu các giá trị kiểu string.

Activity cung cấp các phương thức cho việc lưu trữ  instance state vào Bundle:

  • OnSaveInstanceState – Phương thức sẽ được gọi khi Activity bị destroy. Ta có thể dùng phương thức này để lưu state theo dạng key/value.
  • OnRestoreInstanceState – Phương thức được gọi sau khi OnStart được gọi, cung cấp cơ hội cho Activity phục hồi state sau khi quá trình khởi tạo hoàn tất.

Ví dụ

Đoạn code làm tăng biến c khi button incrementCounter được click, và hiển thị giá trị của biến c ra TextView output. Trong phương thức OnCreate ta kiểm tra xem Activity có lưu trạng thái trước đó (giá trị của biến c), bằng cách dùng if để kiểm tra bundle có null hay không nếu không thì thấy giá trị tương ứng với từ khóa “counter” như phương thức OnSaveInstanceState đã lưu:

  • OnRestoreInstanceState Sử dụng cùng bundle với OnCreate được gọi sau OnStart.
  • Giới hạn của Bundle

    Mặc dù với OnSaveInstanceState ta có thể lưu lại các trạng thái dễ dàng tuy nhiên cũng có một số giới hạn:

    • Không phải lúc nào cũng được gọi. Ví dụ, nhấn home hoặc back để thoát Activity sẽ không gọo OnSaveInstanceState.
    • Bundle không được dùng để lưu các object lớn, như image. Trong trường hợp đó ta sử dụng OnRetainNonConfigurationInstance (bên dưới)
    • Data lưu trong bundle theo dạng serialized, nên có thể dẫn đến delay

    Lưu Data phức tạp

    Trong trường hợp cần lưu trữ object lớn, hoặc dữ liệu phức tạp ta có thể sử dụng phương thức OnRetainNonConfigurationInstance. Phương thức đó cho chúng ta lưu các đối tượng theo dạng Java.Lang.Object. Việc lưu như vậy sẽ tránh trường hợp dữ liệu bạn bị load lại tư đầu (ví dụ như từ web service)

    Ví dụ đoạn code search feed từ Twitter và hiển thị ra theo danh sách:

    Trường hợp này nếu chúng ta xoay điện thoại, dữ liệu sẽ load lại tự đầu. Để khắc phục ta nạp lại OnRetainNonConfigurationInstance và bổ sung một số đoạn code như sau:

    Khi xoay mành hình, ta sẽ lấy dữ liệu lưu trước đó qua LastNonConfiguartionInstance và nạp lại cho List

    (Hết)