Task and back stack trong android
Một ứng dụng android
thường sẽ bao gồm nhiều activity
. Mỗi activity
nên được thiết kế xung quanh một kiểu hành động cụ thể mà người dùng có thể thực hiện và bắt đầu các activity
khác. Ví dụ: một ứng dụng email có thể có một activity
để hiển thị một danh sách các thư mới. Khi người dùng chọn một thư, một activity
mới sẽ mở ra để xem thư đó.
Từ một Activity
của ứng dụng này thậm chí có thể bắt đầu một activity
của một ứng dụng khác. Ví dụ: ứng dụng của bạn có chức năng gởi email, thay vì tự viết chức năng này, bạn có thể gọi ứng dụng email, lập tức ứng dụng email sẽ mở màn hình soạn thảo, và sau khi gởi email, activity
của bạn lại tiếp tục và dường như email activity
giống như 1 phần trong ứng dụng của bạn => mặc dù activity
có thể đến từ các ứng dụng khác nhau, nhưng rõ ràng android
đã giúp duy trì trải nghiệm người dùng một cách mượt mà, và cụ thể ở đây android
đã làm việc này bằng cách giữ cả 2 activity
trong cùng một tác vụ (task
).
Bài viết này sẽ bàn xoay quanh chủ đề Task và Back stack trong android.
Task và Back Stack
Định nghĩa
Task
là tập hợp gồm nhiềuactivity
mà người dùng tương tác với ứng dụng khi thực hiện một công việc nhất định. Cácactivity
được sắp xếp trong mộtstack
(được gọi làBack stack
), theo thứ tự mở của mỗiactivity
.
Điều gì xảy ra khi bạn ấn vào app icon
? Khi đó hệ thống sẽ tìm kiếm trong những task
đã tồn tại trước đó, nếu có task
nào của ứng dụng đã tồn tại, ứng dụng sẽ được tiếp tục (resume
, hay là đưa ra foreground
). Ngược lại, nếu ứng dụng chưa đc sử dụng gần đây, một task
mới sẽ được tạo cùng với "main" activity
của ứng dụng như là root
(gốc) của Back stack
, activity này được khai báo với intent-filter
như bên dưới:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Hành vi mặc định của Activity và Task
Khi activity hiện tại bắt đầu một activity khác bằng cách gọi startActivity()
, hệ thống sẽ mặc định push activity mới lên trên cùng (top
) của Back stack
và giữ focus
vào activity này trong foreground. Activity trước đó vẫn sẽ nằm trong stack
nhưng sẽ dừng lại (ở trạng thái stopped
). Khi một activity stop, hệ thống sẽ giữ lại trạng thái UI (giao diện) hiện tại của người dùng.
Khi người dùng ấn nút Back
, activity hiện tại (trên cùng) sẽ được pop ra khỏi Back stack
và bị hủy (ở trạng thái destroyed
), đồng thời activity trước đó sẽ được tiếp tục (resume
) với trạng thái UI được lưu trước đó. Việc này sẽ lặp lại cho đến khi activity cuối cùng được pop ra khỏi Back stack
, lúc này ứng dụng sẽ thoát và trở về màn hình launcher
của device và lúc này task
của ứng dụng đó sẽ không còn tồn tại.
Các activity trong Back stack
sẽ không bao giờ được sắp xếp lại, mà chỉ được push
hay pop
từ stack
theo đặc trưng của một stack
LIFO (LAST IN FIRST OUT).
Một Task là một đơn vị kết dính, nó có thể chuyển xuống background
khi user bắt đầu một task mới hoặc quay về màn hình Home
bằng cách ấn Home button
. Khi ở trong background
tất cả các activity trong task
sẽ ở trạng thái stopped
(lúc này gọi là Background task
), nhưng Back stack
vẫn không bị ảnh hưởng. Task chỉ đơn giản mất đi focus
khi một task khác thay thế.
Note: Nhiều task có thể được lưu giữ cùng lúc trong background. Tuy nhiên, nếu user chạy quá nhiều
background task
tại cùng thời điểm, hệ thống có thể hủy cácbackground activity
để khôi phục bộ nhớ, lúc này trạng thái của activity bị hủy sẽ mất đi.
Các hành vi mặc định đối với activity
và task
:
- Khi
activity A
bắt đầuActivity B
,Activity A
sẽ bị dừng, nhưng hệ thống sẽ giữ lại trạng thái của nó (VD: vị trí scroll, EditText đang được nhập...), Nếu user ấnBack
khi ởB
,Activity A
sẽ tiếp tục với trạng thái được khôi phục. - Khi user rời khỏi
task
bằng cách ấnHome button
(hoặc mởtask
mới),task
hiên tại sẽ được đưa xuốngbackground
. Hệ thống sẽ giữ nguyên trạng thái của cácactivity
trongtask
, nếu sau đó user tiếp tục ứng dụng,task
sẽ được đưa lênforeground
và tiếp tụcactivity
trên cùng của nó. - Khi user ấn
Back button
,activity
trên cùng củaBack stack
sẽ bị hủy vàpop
ra khỏiBack stack
. Lúc nàyactivity
trước đó sẽ được tiếp tục. Khiactivity
bị hủy, hệ thống sẽ không giữ trạng thái của nó. Activity
có thể được khởi tạo nhiều lần, thậm chí từ cáctask
khác.
Back stack và Fragment
Back stack
không chỉ có tác dụng với activity
mà còn có tác dụng với các fragment
. Khi bạn cung cấp 1 FragmentTransaction
để add, replace, remove
một fragment
từ UI, bạn có thể dùng addToBackStack()
để thêm FragmentTransaction
đó vào trong Back stack
.
Khi ấn Back button
, FragmentTransaction
sẽ được đảo ngược hành động trước đó
- added fragment -> removed
- replaced fragment -> restored
- removed fragment -> added.
Mỗi transaction
thêm vào trong Back stack
sẽ đảo ngược đến khi activity
chứa chúng bị xóa khỏi Back stack
.
Custom Task và hành vi của Back Stack
Có những hành vi mặc định đối với activity
và task
, tuy nhiên android
vẫn cung cấp cho chúng ta các cách khác nhau để thay đổi chúng khi cần thiết.
Nhiều activity giống nhau trong task
Vì các activity
trong Back stack
theo mặc định sẽ không bao giờ được sắp xếp lại, nên sẽ có trường hợp một activity
có thể được tạo nhiều lần nếu nó được khởi tạo từ nhiều lời gọi startActivity()
khác nhau.
Thay vì tạo một task
với quá nhiều activity
giống nhau, ta có thể set launchMode = singleTop
trong AndroidManifest
hoặc thêm cờ (flag
) Intent.FLAG_ACTIVITY_SINGLE_TOP
trong Intent
được gọi , khi đó nếu một instance
của activity
đã tồn tại ở trên cùng (top) của task
hiện tại, thay vì tạo một thực thể mới của activity
đó, hệ thống sẽ chỉ đến activity
đó thông qua hàm onNewIntent()
của nó với Intent
mới chứa các extras data
mới nhất.
Ví dụ: Task hiện tại đang là A-B-C-D, D đang nằm ở đỉnh của task. Lời gọi startActivity D, nếu D được mở với standard
launchMode thì một activity
D mới tạo ra, và task sẽ là A-B-C-D-D. Với singleTop
launchMode thì không có activity mới nào được tạo ra vì D đang ở trên cùng của task hiện tại, vì vậy activity
D hiện tại sẽ gọi onNewIntent()
, task vẫn là A-B-C-D. Trường hợp khác nếu gọi A, B, hoặc C thì activity
tương ứng sẽ tạo ra và thêm vào đỉnh Back stack
ngay cả khi được mở bằng singleTop
launchMode.
Tham khảo thêm các launchMode
và cách quản lý task
tại đây
Back stack và Notification
Sẽ có trường hợp khi thao tác với notification
, bạn mong muốn mở ra một activity
không phải là activtiy
chính (main
, laucher
), mà là một activity
nằm sâu trong ứng dụng (phải cần qua vài thao tác mới mở được màn hình này). VD: bạn muốn mở DetailActivity
:
SplashActivtiy -> ListActivity -> DetailActivtiy
Tuy nhiên, vấn đề nảy sinh là khi ấn Back button
, bạn không muốn thoát ứng dụng ngay mà sẽ muốn ứng dụng chuyển đến màn hình cha (hay trước đó) tương ứng như lúc sử dụng bình thường.
Điều này xảy ra vì khi click vào notification
, một task
mới sẽ tạo ra với duy nhất activity
được chỉ định trong Back stack
. Vì vậy, nếu không có task
nào khác trong background
, khi ấn Back button
, app sẽ thoát.
Giải pháp là sử dụng TaskStackBuilder
: một class đặc biệt để xử lý trường hợp này
// Construct the Intent you want to end up at
Intent detailActivity = new Intent(this, DetailActivity.this);
// Construct the PendingIntent for your Notification
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// This uses android:parentActivityName and
// android.support.PARENT_ACTIVITY meta-data by default
stackBuilder.addNextIntentWithParentStack(detailActivity);
PendingIntent pendingIntent = stackBuilder
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
và trong AndroidManifest
, chỉ rõ activity
cha của DetailActivity
<activity
android:name=".DetailActivity"
android:label="@string/title_activity_order_detail"
android:launchMode="singleTask"
android:parentActivityName=".ListActivity"/>
Note:
addNextIntentWithParentStack()
là một cách ngắn gọn để điều chỉnh cho acitivity
được mở ra từ notification
hoạt động theo cách bạn muốn: mở Parent Activity
khi nhấn Back button
. android:parentActivityName="PARENT_ACTIVITY"
để chỉ ra activity
cha cụ thể (Xem thêm tại đây)
Tham khảo:
https://medium.com/google-developers/tasks-and-the-back-stack-dbb7c3b0f6d4
https://developer.android.com/guide/components/activities/tasks-and-back-stack.html
https://www.youtube.com/watch?list=PLWz5rJ2EKKc-lJo_RGGXL2Psr8vVCTWjM&v=MvIlVsXxXmY
All rights reserved