Lớp học lập trình này nằm trong khóa học về Khái niệm cơ bản về Android Kotlin. Bạn sẽ nhận được nhiều giá trị nhất từ khóa học này nếu bạn làm việc qua các lớp học lập trình theo trình tự. Tất cả các lớp học lập trình trong khóa học đều có trên trang đích của các lớp học lập trình cơ bản về Android Kotlin.
Giới thiệu
Hầu hết các ứng dụng thực tế đều cần thực hiện các tác vụ trong nền trong thời gian dài. Ví dụ: một ứng dụng có thể tải tệp lên máy chủ, đồng bộ hóa dữ liệu từ máy chủ và lưu vào cơ sở dữ liệu Room
, gửi nhật ký đến máy chủ hoặc thực thi các thao tác đắt tiền đối với dữ liệu. Những thao tác như vậy phải được thực hiện trong nền, ngoài luồng giao diện người dùng (chuỗi chính). Tác vụ trong nền sử dụng tài nguyên có giới hạn trên thiết bị, chẳng hạn như RAM và pin. Việc này có thể dẫn đến trải nghiệm kém cho người dùng nếu không được xử lý đúng cách.
Trong lớp học lập trình này, bạn học cách sử dụng WorkManager
để lên lịch tác vụ trong nền một cách tối ưu và hiệu quả. Để tìm hiểu thêm về các giải pháp có sẵn khác để xử lý nền trong Android, hãy xem phần Hướng dẫn về việc xử lý nền.
Kiến thức bạn cần có
- Cách sử dụng Thành phần cấu trúc Android
ViewModel
,LiveData
vàRoom
. - Cách biến đổi trên lớp
LiveData
. - Cách xây dựng và khởi chạy coroutine.
- Cách sử dụng bộ chuyển đổi liên kết trong liên kết dữ liệu.
- Cách tải dữ liệu đã lưu vào bộ nhớ đệm bằng mẫu kho lưu trữ.
Kiến thức bạn sẽ học được
- Cách tạo
Worker
, đại diện cho một đơn vị tác vụ. - Cách tạo
WorkRequest
để yêu cầu thực hiện tác vụ. - Cách thêm các hạn chế vào
WorkRequest
để xác định cách thức và thời điểm nhân viên sẽ chạy. - Cách dùng
WorkManager
để lên lịch các việc cần làm trong nền.
Bạn sẽ thực hiện
- Tạo một nhân viên để thực thi một tác vụ trong nền để tìm nạp trước danh sách phát video DevBytes từ mạng.
- Lên lịch cho nhân viên chạy định kỳ.
- Thêm các hạn chế vào
WorkRequest
. - Lên lịch
WorkRequest
định kỳ được thực thi một lần mỗi ngày.
Trong lớp học lập trình này, bạn làm việc trên ứng dụng DevBytes mà bạn đã phát triển trong một lớp học lập trình trước đó. (Nếu không có ứng dụng này, bạn có thể tải mã dành cho người mới bắt đầu xuống đối với bài học này.)
Ứng dụng DevBytes hiển thị danh sách các video DevByte. Đây là những video hướng dẫn ngắn do nhóm quan hệ nhà phát triển Google Android tạo ra. Video giới thiệu các tính năng dành cho nhà phát triển và các phương pháp hay nhất để phát triển Android.
Bạn cải thiện trải nghiệm người dùng trong ứng dụng bằng cách tìm nạp trước video mỗi ngày một lần. Việc này giúp đảm bảo rằng người dùng sẽ nhận được nội dung mới ngay khi họ mở ứng dụng.
Trong nhiệm vụ này, bạn tải xuống và kiểm tra mã dành cho người mới bắt đầu.
Bước 1: Tải xuống và chạy ứng dụng dành cho người mới bắt đầu
Bạn có thể tiếp tục làm việc qua ứng dụng DevBytes mà bạn đã xây dựng trong lớp học lập trình trước đây (nếu bạn đã cài đặt chương trình này). Hoặc bạn có thể tải ứng dụng dành cho người mới bắt đầu xuống.
Trong nhiệm vụ này, bạn tải xuống và chạy ứng dụng dành cho người mới bắt đầu và kiểm tra mã dành cho người mới bắt đầu.
- Nếu bạn chưa có ứng dụng DevBytes, hãy tải xuống mã khởi động DevBytes cho lớp học lập trình này từ dự án DevBytesRepository từ GitHub.
- Giải nén mã rồi mở dự án trong Android Studio.
- Kết nối thiết bị thử nghiệm hoặc trình mô phỏng của bạn với Internet nếu thiết bị chưa được kết nối. Tạo và chạy ứng dụng. Ứng dụng tìm nạp danh sách các video DevByte từ mạng và hiển thị các video đó.
- Trong ứng dụng YouTube, hãy nhấn vào một video bất kỳ để mở video trong ứng dụng YouTube.
Bước 2: Khám phá mã
Ứng dụng dành cho người mới bắt đầu có rất nhiều mã đã được giới thiệu trong lớp học lập trình trước đó. Mã bắt đầu cho lớp học lập trình này có mô-đun kết nối mạng, giao diện người dùng, bộ nhớ đệm ngoại tuyến và kho lưu trữ. Bạn có thể tập trung vào việc lên lịch tác vụ trong nền bằng cách sử dụng WorkManager
.
- Trong Android Studio, hãy mở rộng tất cả các gói.
- Khám phá gói
database
. Gói này chứa các thực thể cơ sở dữ liệu và cơ sở dữ liệu cục bộ, được triển khai bằngRoom
. - Khám phá gói
repository
. Gói này chứa lớpVideosRepository
trừu tượng hóa lớp dữ liệu trong phần còn lại của ứng dụng. - Khám phá phần còn lại của mã dành cho người mới bắt đầu và sử dụng lớp học lập trình trước đó với sự trợ giúp của chúng tôi.
WorkManager
là một trong các Thành phần cấu trúc Android và một phần của Android Jetpack. WorkManager
dành cho tác vụ trong nền, có thể trì hoãn và yêu cầu thực thi được đảm bảo:
- Có thể trì hoãn có nghĩa là tác vụ không bắt buộc phải chạy ngay lập tức. Ví dụ: việc gửi dữ liệu phân tích đến máy chủ hoặc đồng bộ hóa cơ sở dữ liệu trong nền là công việc có thể bị trì hoãn.
- Thực thi được đảm bảo có nghĩa là tác vụ sẽ chạy ngay cả khi ứng dụng thoát hoặc thiết bị khởi động lại.
Mặc dù WorkManager
chạy tính năng hoạt động trong nền, nhưng công cụ này vẫn xử lý các vấn đề về khả năng tương thích và các phương pháp hay nhất về pin và tình trạng hệ thống. WorkManager
cung cấp khả năng tương thích trở lại API cấp 14. WorkManager
chọn cách thích hợp để lên lịch cho một tác vụ trong nền, tuỳ thuộc vào cấp độ API thiết bị. Tài khoản này có thể sử dụng JobScheduler
(trên API 23 trở lên) hoặc kết hợp giữa AlarmManager
và BroadcastReceiver
.
WorkManager
cũng cho phép bạn đặt tiêu chí về thời điểm chạy tác vụ trong nền. Ví dụ: bạn có thể muốn tác vụ chỉ chạy khi trạng thái pin, trạng thái mạng hoặc trạng thái sạc đáp ứng một số tiêu chí nhất định. Bạn sẽ tìm hiểu cách đặt các quy định ràng buộc sau này trong lớp học lập trình này.
Trong lớp học lập trình này, bạn lên lịch để tìm nạp trước danh sách phát video DevBytes từ mạng mỗi ngày một lần. Để lên lịch cho việc cần làm này, bạn cần sử dụng thư viện WorkManager
.
- Mở tệp
build.gradle (Module:app)
và thêm phần phụ thuộcWorkManager
vào dự án.
Nếu bạn dùng phiên bản mới nhất của thư viện, thì ứng dụng giải pháp sẽ biên dịch như dự kiến. Nếu không, hãy thử giải quyết vấn đề hoặc chuyển về phiên bản thư viện hiển thị bên dưới.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
- Đồng bộ hóa dự án của bạn và đảm bảo không có lỗi biên dịch.
Trước khi bạn thêm mã vào dự án, hãy làm quen với các lớp sau trong thư viện WorkManager
:
Worker
Lớp này là nơi bạn xác định tác vụ thực tế (thao tác) chạy trong nền. Bạn mở rộng lớp này và ghi đè phương thứcdoWork()
. Phương thứcdoWork()
là nơi bạn đặt mã được thực hiện trong nền, chẳng hạn như đồng bộ hóa dữ liệu với máy chủ hoặc xử lý hình ảnh. Bạn triển khaiWorker
trong tác vụ này.WorkRequest
Lớp này đại diện cho một yêu cầu chạy trình chạy trong nền. Sử dụngWorkRequest
để định cấu hình cách và thời điểm chạy tác vụ của nhân viên, với sự trợ giúp củaConstraints
, chẳng hạn như thiết bị đã cắm nguồn hoặc kết nối Wi-Fi. Bạn triển khaiWorkRequest
trong một tác vụ sau này.WorkManager
Lớp học này sẽ lên lịch và chạyWorkRequest
của bạn.WorkManager
lên lịch các yêu cầu tác vụ theo cách lan truyền tải trên các tài nguyên hệ thống, trong khi vẫn tôn trọng các hạn chế mà bạn chỉ định. Bạn triển khaiWorkManager
trong một tác vụ sau này.
Bước 1: Tạo nhân viên
Trong nhiệm vụ này, bạn thêm một Worker
để tìm nạp trước danh sách phát video DevBytes trong nền.
- Trong gói
devbyteviewer
, hãy tạo một gói mới có tên làwork
. - Trong gói
work
, hãy tạo một lớp Kotlin mới có tên làRefreshDataWorker
. - Mở rộng lớp
RefreshDataWorker
từ lớpCoroutineWorker
. Chuyển tham sốcontext
vàWorkerParameters
dưới dạng tham số hàm dựng.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
}
- Để giải quyết lỗi lớp trừu tượng, hãy ghi đè phương thức
doWork()
bên trong lớpRefreshDataWorker
.
override suspend fun doWork(): Result {
return Result.success()
}
Hàm tạm ngưng là một hàm có thể tạm dừng và tiếp tục sau đó. Hàm tạm ngưng có thể thực thi thao tác thực hiện lâu và đợi thao tác này hoàn tất mà không chặn chuỗi chính.
Bước 2: Triển khai doWork()
Phương thức doWork()
bên trong lớp Worker
được gọi trên một luồng trong nền. Phương thức này thực hiện tác vụ một cách đồng bộ và sẽ trả về một đối tượng ListenableWorker.Result
. Hệ thống Android cho Worker
tối đa 10 phút để hoàn thành quá trình thực thi và trả về đối tượng ListenableWorker.Result
. Sau khi thời gian này hết hạn, hệ thống sẽ buộc dừng Worker
.
Để tạo một đối tượng ListenableWorker.Result
, hãy gọi một trong những phương thức tĩnh sau đây để cho biết trạng thái hoàn thành của tác vụ trong nền:
Result.success()
—công việc đã hoàn tất thành công.Result.failure()
—công việc đã hoàn tất với một lỗi vĩnh viễn.Result.retry()
—công việc gặp phải lỗi tạm thời và cần được thử lại.
Trong tác vụ này, bạn triển khai phương thức doWork()
để tìm nạp danh sách phát video DevBytes từ mạng. Bạn có thể sử dụng lại các phương thức hiện có trong lớp VideosRepository
để truy xuất dữ liệu từ mạng đó.
- Trong lớp
RefreshDataWorker
, bên trongdoWork()
, hãy tạo và tạo thực thể cho đối tượngVideosDatabase
và đối tượngVideosRepository
.
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
return Result.success()
}
- Trong lớp
RefreshDataWorker
, bên trongdoWork()
, phía trên câu lệnhreturn
, hãy gọi phương thứcrefreshVideos()
bên trong một khốitry
. Thêm nhật ký để theo dõi khi chạy Worker.
try {
repository.refreshVideos( )
Timber.d("Work request for sync is run")
} catch (e: HttpException) {
return Result.retry()
}
Để giải quyết "Chưa giải quyết tệp đối chiếu" lỗi, hãy nhập retrofit2.HttpException
.
- Dưới đây là lớp học đầy đủ của
RefreshDataWorker
để bạn tham khảo:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
try {
repository.refreshVideos()
} catch (e: HttpException) {
return Result.retry()
}
return Result.success()
}
}
Worker
xác định đơn vị tác vụ và WorkRequest
xác định cách thức và thời điểm sẽ chạy tác vụ. Có hai cách triển khai cụ thể cho lớp WorkRequest
:
- Lớp
OneTimeWorkRequest
dành cho các việc cần làm một lần. (Việc cần làm một lần chỉ xảy ra một lần.) - Lớp
PeriodicWorkRequest
dành cho bài tập định kỳ, bài tập lặp lại theo khoảng thời gian.
Việc cần làm có thể diễn ra một lần hoặc định kỳ, vì vậy, hãy chọn lớp cho phù hợp. Để biết thêm thông tin về cách lên lịch tác vụ định kỳ, hãy xem tài liệu về tác vụ định kỳ.
Trong việc cần làm này, bạn xác định và lên lịch cho WorkRequest
để chạy trình chạy mà bạn đã tạo trong việc trước đó.
Bước 1: Thiết lập công việc định kỳ
Trong ứng dụng Android, lớp Application
là lớp cơ sở chứa tất cả các thành phần khác, chẳng hạn như hoạt động và dịch vụ. Khi quá trình ứng dụng hoặc gói của bạn được tạo, lớp Application
(hoặc bất kỳ lớp con nào của Application
) đều được tạo bản sao trước bất kỳ lớp nào khác.
Trong ứng dụng mẫu này, lớp DevByteApplication
là lớp con của lớp Application
. Lớp DevByteApplication
là một nơi tốt để lên lịch cho WorkManager
.
- Trong lớp
DevByteApplication
, hãy tạo một phương thức có tên làsetupRecurringWork()
để thiết lập tác vụ trong nền định kỳ.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
- Bên trong phương thức
setupRecurringWork()
, hãy tạo và khởi tạo một yêu cầu tác vụ định kỳ để chạy mỗi ngày một lần, bằng cách sử dụng phương thứcPeriodicWorkRequestBuilder()
. Chuyển vào lớpRefreshDataWorker
mà bạn đã tạo trong việc cần làm trước đó. Chuyển trong khoảng thời gian lặp lại là1
với đơn vị thời gian làTimeUnit.
DAYS
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.build()
Để khắc phục lỗi này, hãy nhập java.util.concurrent.TimeUnit
.
Bước 2: Lên lịch WorkRequest bằng WorkManager
Sau khi xác định WorkRequest
, bạn có thể lên lịch bằng WorkManager
bằng cách sử dụng phương thức enqueueUniquePeriodicWork()
. Phương pháp này cho phép bạn thêm một tên PeriodicWorkRequest
riêng vào hàng đợi. Tại đây, chỉ một PeriodicWorkRequest
tên cụ thể có thể hoạt động tại một thời điểm.
Ví dụ: bạn có thể chỉ muốn một hoạt động đồng bộ hóa hoạt động. Nếu một hoạt động đồng bộ hóa đang chờ xử lý, bạn có thể chọn cho phép hoạt động này hoặc thay thế hoạt động đó bằng tác vụ mới, bằng cách sử dụng ExistingPeriodicWorkPolicy.
Để tìm hiểu thêm về cách lên lịch cho WorkRequest
, hãy xem tài liệu WorkManager
.
- Trong lớp
RefreshDataWorker
, ở đầu lớp, hãy thêm một đối tượng companion. Xác định tên công việc để nhận dạng duy nhất nhân viên này.
companion object {
const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
- Trong lớp
DevByteApplication
, ở cuối phương thứcsetupRecurringWork()
, hãy lên lịch bài tập bằng phương thứcenqueueUniquePeriodicWork()
. Chuyển giá trị enumKEEP
cho ExistingPeriodicWorkPolicy. ChuyểnrepeatingRequest
vào dưới dạng thông sốPeriodicWorkRequest
.
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
Nếu tác vụ đang chờ xử lý (chưa hoàn thành) có cùng tên, thông số ExistingPeriodicWorkPolicy.
KEEP
sẽ làm cho WorkManager
lưu giữ tác vụ định kỳ trước đó và loại bỏ yêu cầu tác vụ mới.
- Ở đầu lớp
DevByteApplication
, hãy tạo một đối tượngCoroutineScope
. ChuyểnDispatchers.Default
làm tham số hàm dựng.
private val applicationScope = CoroutineScope(Dispatchers.Default)
- Trong lớp
DevByteApplication
, hãy thêm một phương thức mới có tên làdelayedInit()
để bắt đầu một coroutine.
private fun delayedInit() {
applicationScope.launch {
}
}
- Bên trong phương thức
delayedInit()
, hãy gọisetupRecurringWork()
. - Di chuyển quá trình khởi chạy Timber từ phương thức
onCreate()
sang phương thứcdelayedInit()
.
private fun delayedInit() {
applicationScope.launch {
Timber.plant(Timber.DebugTree())
setupRecurringWork()
}
}
- Trong lớp
DevByteApplication
, ở cuối phương thứconCreate()
, hãy thêm một lệnh gọi vào phương thứcdelayedInit()
.
override fun onCreate() {
super.onCreate()
delayedInit()
}
- Mở ngăn Logcat ở cuối cửa sổ Android Studio. Lọc trên
RefreshDataWorker
. - Chạy ứng dụng.
WorkManager
lên lịch công việc định kỳ của bạn ngay lập tức.
Trong ngăn Logcat, hãy chú ý những câu lệnh nhật ký cho thấy rằng yêu cầu tác vụ được lên lịch, sau đó chạy thành công.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Nhật ký WM-WorkerWrapper
được hiển thị từ thư viện WorkManager
, do đó bạn không thể thay đổi thông điệp nhật ký này.
Bước 3: (Không bắt buộc) Lên lịch cho WorkRequest trong khoảng thời gian tối thiểu
Trong bước này, bạn giảm khoảng thời gian từ 1 ngày xuống còn 15 phút. Bạn thực hiện việc này để có thể xem nhật ký cho một yêu cầu tác vụ định kỳ trong thực tế.
- Trong lớp
DevByteApplication
, bên trong phương thứcsetupRecurringWork()
, hãy nhận xét định nghĩa hiện tạirepeatingRequest
. Thêm một yêu cầu tác vụ mới với khoảng thời gian lặp lại định kỳ là15
phút.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
// .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.build()
- Mở ngăn Logcat trong Android Studio rồi lọc trên
RefreshDataWorker
. Để xóa các nhật ký trước đó, hãy nhấp vào biểu tượng Xóa logcat.
- Chạy ứng dụng và
WorkManager
lên lịch tác vụ định kỳ của bạn ngay lập tức. Trong ngăn Logcat, hãy lưu ý nhật ký — yêu cầu tác vụ sẽ chạy 15 phút một lần. Hãy đợi 15 phút để xem một nhóm nhật ký yêu cầu công việc khác. Bạn có thể để ứng dụng chạy hoặc đóng ứng dụng. Trình quản lý công việc vẫn sẽ chạy.
Lưu ý rằng khoảng thời gian này đôi khi ít hơn 15 phút và đôi khi hơn 15 phút. (Thời gian chính xác phải được tối ưu hóa pin trên hệ điều hành).
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
Xin chúc mừng! Bạn đã tạo một nhân viên và lên lịch yêu cầu làm việc với WorkManager
. Nhưng có một vấn đề: bạn không chỉ định bất kỳ ràng buộc nào. WorkManager
sẽ lên lịch làm việc một lần mỗi ngày, ngay cả khi thiết bị sắp hết pin, đang ngủ hoặc không có kết nối mạng. Điều này sẽ ảnh hưởng đến pin và hiệu suất của thiết bị, đồng thời có thể dẫn đến trải nghiệm người dùng kém.
Trong nhiệm vụ tiếp theo, hãy giải quyết vấn đề này bằng cách thêm các hạn chế.
Trong việc cần làm trước đó, bạn đã sử dụng WorkManager
để lên lịch yêu cầu tác vụ. Trong nhiệm vụ này, bạn thêm các tiêu chí về thời điểm thực thi tác vụ.
Khi xác định WorkRequest
, bạn có thể chỉ định các hạn chế đối với thời điểm sẽ chạy Worker
. Ví dụ: bạn có thể muốn chỉ định rằng tác vụ sẽ chỉ chạy khi thiết bị ở trạng thái rảnh, hoặc chỉ khi thiết bị được cắm nguồn và kết nối Wi-Fi. Bạn cũng có thể chỉ định một chính sách đợi để thử lại bài tập. Các hạn chế được hỗ trợ là các phương thức đã đặt trong Constraints.Builder
. Để tìm hiểu thêm, hãy xem bài viết Xác định yêu cầu tác vụ.
Bước 1: Thêm một đối tượng Constraints và đặt một hạn chế
Trong bước này, bạn tạo một đối tượng Constraints
và đặt một hạn chế cho đối tượng, đó là một hạn chế theo loại mạng. (Dễ dàng nhận thấy các nhật ký chỉ có một hạn chế. Ở bước sau, bạn thêm các hạn chế khác.)
- Trong lớp
DevByteApplication
, ở đầusetupRecurringWork()
, hãy xác địnhval
của loạiConstraints
. Hãy sử dụng phương thứcConstraints.Builder()
.
val constraints = Constraints.Builder()
Để khắc phục lỗi này, hãy nhập androidx.work.Constraints
.
- Hãy dùng phương thức
setRequiredNetworkType()
để thêm một hạn chế loại mạng vào đối tượngconstraints
. Sử dụng giá trị enumUNMETERED
để yêu cầu tác vụ sẽ chỉ chạy khi thiết bị đang ở trên mạng không đo lượng dữ liệu.
.setRequiredNetworkType(NetworkType.UNMETERED)
- Dùng phương thức
build()
để tạo các hạn chế từ trình tạo.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
Bây giờ, bạn cần đặt đối tượng Constraints
mới tạo thành yêu cầu tác vụ.
- Trong lớp
DevByteApplication
, bên trong phương thứcsetupRecurringWork()
, hãy đặt đối tượngConstraints
thành yêu cầu tác vụ định kỳrepeatingRequest
. Để đặt các hạn chế, hãy thêm phương thứcsetConstraints()
phía trên lệnh gọi phương thứcbuild()
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
Bước 2: Chạy ứng dụng và nhận nhật ký
Trong bước này, bạn chạy ứng dụng và nhận thấy yêu cầu tác vụ bị hạn chế đang chạy trong nền theo khoảng thời gian.
- Gỡ cài đặt ứng dụng khỏi thiết bị hoặc trình mô phỏng để hủy mọi việc cần làm đã lên lịch trước đó.
- Mở ngăn Logcat trong Android Studio. Trong ngăn Logcat, hãy xóa các nhật ký trước đó bằng cách nhấp vào biểu tượng Xóa logcat
ở bên trái. Lọc trên
work
. - Hãy tắt Wi-Fi trong thiết bị hoặc trình mô phỏng để bạn có thể xem cách các hạn chế hoạt động. Mã hiện tại chỉ đặt một hạn chế, cho biết rằng yêu cầu chỉ chạy trên mạng không đo lượng dữ liệu. Vì Wi-Fi đang tắt nên thiết bị sẽ không kết nối mạng, có đo lượng dữ liệu hoặc không đo lượng dữ liệu. Do đó, hạn chế này sẽ không được đáp ứng.
- Chạy ứng dụng và nhận thấy ngăn Logcat.
WorkManager
lập lịch tác vụ trong nền ngay lập tức. Vì không đáp ứng giới hạn mạng nên tác vụ sẽ không chạy.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Bật Wi-Fi trong thiết bị hoặc trình mô phỏng và xem ngăn Logcat. Giờ đây, tác vụ trong nền đã lên lịch chạy khoảng 15 phút một lần, miễn là giới hạn mạng được đáp ứng.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Bước 3: Thêm các hạn chế khác
Trong bước này, bạn thêm các hạn chế sau vào PeriodicWorkRequest
:
- Pin yếu.
- Đang sạc thiết bị.
- Thiết bị không hoạt động; chỉ hoạt động trong API cấp 23 (Android M) trở lên.
Triển khai các mục sau trong lớp DevByteApplication
.
- Trong lớp
DevByteApplication
, bên trong phương thứcsetupRecurringWork()
, hãy cho biết rằng yêu cầu tác vụ chỉ chạy nếu pin yếu. Thêm hạn chế trước lệnh gọi phương thứcbuild()
và sử dụng phương thứcsetRequiresBatteryNotLow()
.
.setRequiresBatteryNotLow(true)
- Hãy cập nhật yêu cầu tác vụ để yêu cầu chỉ chạy khi thiết bị đang sạc. Thêm hạn chế trước lệnh gọi phương thức
build()
và sử dụng phương thứcsetRequiresCharging()
.
.setRequiresCharging(true)
- Hãy cập nhật yêu cầu tác vụ để yêu cầu chỉ chạy khi thiết bị ở trạng thái rảnh. Thêm hạn chế trước lệnh gọi phương thức
build()
và sử dụng phương thứcsetRequiresDeviceIdle()
. Hạn chế này chỉ chạy yêu cầu tác vụ khi người dùng không chủ động sử dụng thiết bị. Tính năng này chỉ hoạt động trên Android 6.0 (Marshmallow) trở lên, vì vậy, hãy thêm một điều kiện cho SDK phiên bảnM
trở lên.
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
Sau đây là định nghĩa đầy đủ về đối tượng constraints
.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
- Bên trong phương thức
setupRecurringWork()
, hãy thay đổi khoảng thời gian yêu cầu trở lại một lần mỗi ngày.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Dưới đây là quy trình triển khai hoàn chỉnh của phương thức setupRecurringWork()
, cùng với nhật ký để bạn có thể theo dõi thời điểm yêu cầu tác vụ định kỳ được lên lịch.
private fun setupRecurringWork() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Timber.d("Periodic Work request for sync is scheduled")
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
}
- Để xóa yêu cầu tác vụ đã lên lịch trước đó, hãy gỡ cài đặt ứng dụng DevBytes khỏi thiết bị hoặc trình mô phỏng của bạn.
- Chạy ứng dụng và
WorkManager
sẽ lên lịch yêu cầu tác vụ ngay lập tức. Yêu cầu tác vụ chạy một lần mỗi ngày, khi tất cả các hạn chế được đáp ứng. - Yêu cầu tác vụ này sẽ chạy trong nền khi ứng dụng được cài đặt, ngay cả khi ứng dụng không chạy. Do đó, bạn nên gỡ cài đặt ứng dụng này khỏi điện thoại.
Thật tuyệt! Bạn đã triển khai và lên lịch yêu cầu tác vụ thân thiện với pin cho việc tìm nạp trước video hàng ngày trong ứng dụng DevBytes. WorkManager
sẽ lên lịch và chạy tác vụ, tối ưu hóa tài nguyên hệ thống. Người dùng và pin của họ sẽ rất vui.
Dự án Android Studio: DevBytesWorkManager.
- API
WorkManager
giúp bạn dễ dàng lên lịch các tác vụ có thể trì hoãn, không đồng bộ mà phải chạy một cách đáng tin cậy. - Hầu hết các ứng dụng thực tế đều cần thực hiện các tác vụ trong nền trong thời gian dài. Để lên lịch một tác vụ trong nền một cách tối ưu và hiệu quả, hãy dùng
WorkManager
. - Các lớp học chính trong thư viện
WorkManager
làWorker
,WorkRequest
vàWorkManager
. - Lớp
Worker
đại diện cho một đơn vị tác vụ. Để triển khai tác vụ trong nền, hãy mở rộng lớpWorker
và ghi đè phương thứcdoWork()
. - Lớp
WorkRequest
biểu thị một yêu cầu thực hiện đơn vị tác vụ.WorkRequest
là lớp cơ sở để chỉ định các thông số cho tác vụ mà bạn lập lịch trongWorkManager
. - Có hai cách triển khai cụ thể cho lớp
WorkRequest
:OneTimeWorkRequest
cho các tác vụ một lần vàPeriodicWorkRequest
cho các yêu cầu tác vụ định kỳ. - Khi xác định
WorkRequest
, bạn có thể chỉ địnhConstraints
cho biết thời điểmWorker
sẽ chạy. Các hạn chế bao gồm: - Để thêm các hạn chế vào
WorkRequest
, hãy dùng các phương thức đã đặt trong tài liệu vềConstraints.Builder
. Ví dụ: để cho biết rằngWorkRequest
không nên chạy nếu pin thiết bị yếu, hãy sử dụng phương thức đặtsetRequiresBatteryNotLow()
. - Sau khi bạn xác định
WorkRequest
, hãy chuyển việc cần làm sang hệ thống Android. Để làm việc này, hãy lên lịch cho tác vụ bằng một trongWorkManager
enqueue
phương thức. - Thời gian chính xác mà
Worker
được thực thi phụ thuộc vào các hạn chế được sử dụng trongWorkRequest
và các hoạt động tối ưu hóa hệ thống.WorkManager
được thiết kế để mang lại hành vi tốt nhất có thể, dựa trên các hạn chế này.
Khóa học từ Udacity:
Tài liệu dành cho nhà phát triển Android:
- Xác định Yêu cầu công việc
WorkManager
- Bắt đầu sử dụng WorkManager
- Làm việc định kỳ
- Hướng dẫn xử lý nền
Các tài liệu khác:
Phần này liệt kê các bài tập về nhà có thể được giao cho học viên đang làm việc qua lớp học lập trình này trong khóa học do người hướng dẫn tổ chức. Người hướng dẫn có thể làm những việc sau:
- Giao bài tập về nhà nếu được yêu cầu.
- Trao đổi với học viên cách nộp bài tập về nhà.
- Chấm điểm bài tập về nhà.
Người hướng dẫn có thể sử dụng những đề xuất này ít hay nhiều tùy ý. Do đó, họ có thể thoải mái giao bất kỳ bài tập về nhà nào khác mà họ cảm thấy phù hợp.
Nếu bạn đang tự mình làm việc qua lớp học lập trình này, hãy thoải mái sử dụng các bài tập về nhà này để kiểm tra kiến thức của bạn.
Câu hỏi 1
Đâu là cách triển khai cụ thể của lớp WorkRequest
?
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest
và PeriodicWorkRequest
▢ OneTimeWorkRequest
và RecurringWorkRequest
▢ OneTimeOffWorkRequest
và RecurringWorkRequest
Câu hỏi 2
WorkManager
dùng lớp nào sau đây để lên lịch việc cần làm trong nền cho API 23 trở lên?
▢ Chỉ JobScheduler
▢ BroadcastReceiver
và AlarmManager
▢ AlarmManager
và JobScheduler
▢ Scheduler
và BroadcastReceiver
Câu hỏi 3
Bạn sử dụng API nào để thêm các điều kiện ràng buộc vào WorkRequest
?
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
Chuyển sang bài học tiếp theo:
Để biết đường liên kết đến các lớp học lập trình khác trong khóa học này, hãy xem trang đích của các lớp học lập trình cơ bản về Android Kotlin.