使用 WorkManager 管理后台和前台工作
??
隨著設(shè)備性能提升和軟件生態(tài)發(fā)展,越來越多的 Android 應(yīng)用需要執(zhí)行相對(duì)更復(fù)雜的網(wǎng)絡(luò)、異步和離線等任務(wù)。例如用戶想要離線觀看某個(gè)視頻,又不想一直停留在應(yīng)用界面等待下載完成,那么就需要以一定的方式讓這些離線的過程在后臺(tái)運(yùn)行。再比如您想將一段精彩的 Vlog 分享到社交媒體,肯定也會(huì)希望視頻上傳時(shí)不會(huì)影響到自己繼續(xù)使用設(shè)備。這就涉及到了我們今天分享的主題: 使用 WorkManager 管理后臺(tái)和前臺(tái)工作。
如果您更喜歡通過視頻了解此內(nèi)容,請(qǐng)?jiān)诖颂幉榭?
現(xiàn)代 WorkManager API 已發(fā)布
Bilibili 視頻鏈接
https://www.bilibili.com/video/BV16S4y1r7o9/
本文將著重探討 WorkManager 的 API 以及用法,幫助您深入了解它的運(yùn)行機(jī)制,以及在實(shí)際開發(fā)中的使用方式。近期也將會(huì)有另一篇關(guān)于在 Android Studio 中如何更好地使用 WorkManager 的文章,敬請(qǐng)關(guān)注。
從首個(gè)穩(wěn)定版本發(fā)布以來,WorkManager 提供了一些基礎(chǔ) API,幫助您定義工作、放入隊(duì)列、依次執(zhí)行,且在工作完成時(shí)通知您的應(yīng)用。以功能劃分分類,這些基礎(chǔ) API 包括:
最初的版本中,這些工作只能被定義為延遲執(zhí)行,也就是它們會(huì)在定義之后延期再開始執(zhí)行。通過這種延期執(zhí)行策略,一些不緊急或優(yōu)先級(jí)不高的任務(wù)將會(huì)推后執(zhí)行。
WorkManager 的延期執(zhí)行會(huì)充分考慮設(shè)備的低電耗狀態(tài),以及應(yīng)用的待機(jī)存儲(chǔ)分區(qū),因此您不必考慮工作需要在哪個(gè)具體時(shí)間被執(zhí)行,這些都交給 WorkManager 考慮即可。
WorkManager 支持對(duì)給定工作運(yùn)行設(shè)定約束條件,約束可確保將工作延遲到滿足最佳條件時(shí)運(yùn)行。例如,僅在設(shè)備采用不按流量計(jì)費(fèi)的網(wǎng)絡(luò)連接時(shí)、當(dāng)設(shè)備處于空閑狀態(tài)或者有足夠的電量時(shí)運(yùn)行。您可以專心開發(fā)應(yīng)用的其他功能,將對(duì)工作條件的檢查交給 WorkManager。
-
約束
https://developer.android.google.cn/topic/libraries/architecture/workmanager/how-to/define-work#work-constraints
我們知道,工作之間是可能存在依賴關(guān)系的。比如您正在開發(fā)一個(gè)視頻編輯應(yīng)用,當(dāng)剪輯完成后用戶可能需要分享到社交媒體,于是您的應(yīng)用需要依次渲染若干個(gè)視頻片段,然后將它們一起上傳到視頻服務(wù)。這個(gè)過程是具有先后次序的,也就是上傳工作依賴渲染工作的完成。
再舉另外一個(gè)例子,當(dāng)您的應(yīng)用完成與后端同步數(shù)據(jù)后,也許您希望同步過程中產(chǎn)生的本地日志文件被及時(shí)清理,或者是將來自后端的新數(shù)據(jù)填充到本地?cái)?shù)據(jù)庫(kù)中。于是您可以請(qǐng)求 WorkManager 按照順序或者并行執(zhí)行這些工作,從而實(shí)現(xiàn)各個(gè)工作之間無縫銜接。而 WorkManager 會(huì)在確保所有給定條件都滿足后再運(yùn)行后續(xù)的 Worker。
https://developer.android.google.cn/reference/androidx/work/Worker
很多具備與服務(wù)器同步功能的應(yīng)用都具有這樣的特點(diǎn): 應(yīng)用與后端服務(wù)器的同步往往不是一次性的,它可能是需要多次執(zhí)行的。比如當(dāng)您的應(yīng)用提供在線編輯服務(wù)時(shí),一定需要頻繁將本地的編輯數(shù)據(jù)同步到云端,這就產(chǎn)生了定期執(zhí)行的工作。
由于您可以隨時(shí)檢查某個(gè)工作的狀態(tài),因此對(duì)于定期執(zhí)行的工作而言,整個(gè)生命周期是透明的。您可以知道一個(gè)工作是處于隊(duì)列等待、運(yùn)行中、阻塞還是已完成狀態(tài)。
上述的基礎(chǔ) API 早在我們發(fā)布 WorkManager 的第一個(gè)穩(wěn)定版時(shí)就已經(jīng)提供了。首次在 Android 開發(fā)者峰會(huì)中談到 WorkManager 時(shí),我們把它看作是管理可延期后臺(tái)工作的一個(gè)庫(kù)。如今從底層的角度來看,這種觀點(diǎn)仍然是成立的。但后來我們又添加了更多新功能,并讓 API 更符合現(xiàn)代規(guī)范。
這些新引入的 API 和改進(jìn)的工具在為開發(fā)者提供更大便利的同時(shí),也促使我們重新思考使用 WorkManager 的最佳時(shí)機(jī)。雖然從技術(shù)角度,我們?cè)O(shè)計(jì) WorkManager 的核心思想仍然是正確的,但對(duì)于日益復(fù)雜的開發(fā)生態(tài)而言,WorkManager 的能力已經(jīng)大大超過我們的設(shè)計(jì)預(yù)期。
工作的 “持久化” 特性
WorkManager 可以處理您指派給它的任何類型的工作,因此它已經(jīng)進(jìn)化成了一個(gè)專門處理任務(wù)且值得信賴的好工具。WorkManager 在全局作用域中執(zhí)行您定義的 Worker,這意味著只要您的應(yīng)用還在運(yùn)行,不論是設(shè)備方向的變化,還是 Activity 被回收等,您的工作會(huì)被一直留存。不過單憑這一點(diǎn),還不能稱之擁有 “持久化” 特性,因此 WorkManager 在底層還使用了 Room 數(shù)據(jù)庫(kù)來保證當(dāng)進(jìn)程被結(jié)束或設(shè)備重啟后,您的工作仍然可以執(zhí)行,并有可能從中斷位置繼續(xù)執(zhí)行。
執(zhí)行需要長(zhǎng)時(shí)間運(yùn)行的工作
WorkManager 2.3 版本引入了對(duì)長(zhǎng)時(shí)間運(yùn)行的工作的支持。當(dāng)我們談到長(zhǎng)時(shí)間運(yùn)行的工作時(shí),指的是運(yùn)行時(shí)間超過 10 分鐘執(zhí)行窗口期的工作。通常情況下,一個(gè) Worker 的執(zhí)行窗口期被限定為 10 分鐘。為了能實(shí)現(xiàn)長(zhǎng)時(shí)間運(yùn)行的工作,WorkManager 將 Worker 的生命周期與前臺(tái)服務(wù)的生命周期捆綁在一起。JobScheduler 和進(jìn)程內(nèi)調(diào)度程序 (In-Process Scheduler) 仍然能感知到這種工作的存在。
https://developer.android.google.cn/reference/android/app/job/JobScheduler
由于前臺(tái)服務(wù)掌握著工作執(zhí)行的生命周期,而前臺(tái)服務(wù)又需要向用戶展示通知信息,所以我們向 WorkManager 添加了相關(guān)的 API。用戶的注意力持續(xù)時(shí)間是有限的,所以 WorkManager 提供了 API 讓用戶能方便地通過通知停止長(zhǎng)時(shí)間運(yùn)行的工作。我們來分析一個(gè)長(zhǎng)時(shí)間運(yùn)行工作示例,代碼如下:
class DownloadWorker(context: Context, parameters: WorkerParameters) : CoroutineWorker(context, parameters) {fun notification(progress: String): Notification = TODO()// notification 方法根據(jù)進(jìn)度信息生成一條 Android 通知消息。suspend fun download(inputUrl: String,outputFile: String,callback: suspend (progress: String) -> Unit) = TODO()// 定義一個(gè)用于分塊下載的方法fun createForegroundInfo(progress: String): ForegroundInfo {return ForegroundInfo(id, notification(progress))}override suspend fun doWork(): Result {download(inputUrl, outputFile) { progress -> val progress = "Progress $progress %"setForeground(createForegroundInfo(progress))} // 提供了一個(gè) suspend 標(biāo)記的 doWork 方法,其中調(diào)用下載方法,并顯示最新進(jìn)度信息。return Result.success() } //下載完成后,Worker 只需要返回成功即可 }這里有一個(gè) DownloadWorker 類,它擴(kuò)展自 CoroutineWorker 類。我們會(huì)在這個(gè)類當(dāng)中定義一些輔助方法來簡(jiǎn)化我們的工作。首先是一個(gè) notification 方法,它可以根據(jù)所給定的進(jìn)度信息生成一條 Android 通知消息。接下來我們要定義一個(gè)用于分塊下載的方法,這個(gè)方法接受三個(gè)參數(shù): 下載文件的 URL、文件保存的本地位置、suspend 回調(diào)函數(shù)。每當(dāng)某個(gè)分塊下載狀態(tài)變化時(shí),此回調(diào)就會(huì)被執(zhí)行一次。于是,回調(diào)中攜帶的信息就可以被用來生成一條通知。
CoroutineWorker
https://developer.android.google.cn/reference/kotlin/androidx/work/CoroutineWorker.html
有了這些輔助方法,我們就可以將 WorkManager 執(zhí)行長(zhǎng)時(shí)間運(yùn)行工作所需要的 ForegroundInfo 實(shí)例保存起來。ForegroundInfo 是由通知 ID 和通知實(shí)例組合構(gòu)造而成的,請(qǐng)繼續(xù)參照上述 CoroutineWorker 類的代碼示例。
在這段代碼里,我們提供了一個(gè) suspend 標(biāo)記的 doWork 方法,其中調(diào)用了剛才提到的分塊下載輔助方法。由于每次回調(diào)發(fā)生時(shí)都會(huì)提供一些最新的進(jìn)度信息,所以我們可以利用這些信息來構(gòu)建通知,并調(diào)用 setForeground 方法來向用戶顯示這些通知。這里調(diào)用 setForeground 的操作正是導(dǎo)致 Worker 長(zhǎng)時(shí)間運(yùn)行的原因。下載完成后,Worker 只需要返回成功即可,隨后 WorkManager 會(huì)將 Worker 的執(zhí)行與前臺(tái)服務(wù)解耦分離、清理通知消息,并在必要時(shí)結(jié)束相關(guān)的服務(wù)。因此我們的 Worker 本身并不需要執(zhí)行服務(wù)管理工作。
終止已提交執(zhí)行的工作
用戶可能會(huì)突然改變主意,比如想要取消某個(gè)工作。某個(gè)前臺(tái)運(yùn)行服務(wù)的通知是無法簡(jiǎn)單滑動(dòng)取消的,此前的做法是為這條通知消息添加一個(gè)動(dòng)作,當(dāng)用戶點(diǎn)擊時(shí)會(huì)向 WorkManager 發(fā)送一個(gè)信號(hào),從而按照用戶的意圖終止某項(xiàng)工作。您也可以通過執(zhí)行加急工作來終止,詳見后文。
fun notification(progress: String): Notification {val intent = WorkManager.getInstance(context).createCancelPendingIntent(getId())return NotificationCompat.Builder(applicationContext, id).setContentTitle(title).setContentText(progress)// 其他一些操作.addAction(android.R.drawable.ic_delete, cancel, intent).build() }首先需要?jiǎng)?chuàng)建一個(gè)待處理的 Intent,它可以很方便地取消某項(xiàng)工作。我們需要調(diào)用 getId 方法來獲取這個(gè)工作創(chuàng)建時(shí)的工作請(qǐng)求 ID,然后調(diào)用 createCancelPendingIntent API 創(chuàng)建這個(gè) Intent 實(shí)例。當(dāng)此 Intent 被觸發(fā)時(shí),它會(huì)向 WorkManager 發(fā)送取消工作的信號(hào),從而實(shí)現(xiàn)取消工作的目的。
接下來就要生成帶有自定義動(dòng)作的通知消息了。我們使用 NotificationCompat.Builder 設(shè)置通知的標(biāo)題,然后添加一些文字說明。隨后調(diào)用 addAction 方法將通知中的 “取消” 按鈕與上一步創(chuàng)建的 Intent 關(guān)聯(lián)起來。于是,當(dāng)用戶點(diǎn)擊 “取消” 按鈕時(shí),這個(gè) Intent 就會(huì)被發(fā)送到當(dāng)前正在執(zhí)行這個(gè) Worker 的前臺(tái)服務(wù),從而將其終止。
執(zhí)行加急工作
Android 12 中引入了新的前臺(tái)服務(wù)限制,當(dāng)應(yīng)用在后臺(tái)時(shí)是無法啟動(dòng)前臺(tái)服務(wù)的。因此從 Android 12 開始,調(diào)用 setForegroundAsync 方法會(huì)拋出 Foreground Service Start Not Allowed Exception (不允許啟動(dòng)前臺(tái)服務(wù)) 異常。這種情況下,WorkManager 就派上用場(chǎng)了。WorkManager 2.7 版本中增加了對(duì)加急工作 (expedited work) 的支持,所以接下來將會(huì)向您介紹如何使用 WorkManager 實(shí)現(xiàn)終止已提交執(zhí)行的工作。
https://developer.android.google.cn/jetpack/androidx/releases/work#2.7.0
從用戶的角度來說,加急工作是由用戶發(fā)起的,因此對(duì)用戶而言非常重要。甚至應(yīng)用不在前臺(tái)時(shí),這些工作也需要被啟動(dòng)執(zhí)行。比如聊天應(yīng)用需要下載一條消息中的附件,或者應(yīng)用需要處理付款訂閱的流程。在早于 Android 12 的 API 版本中,加急工作都是由前臺(tái)服務(wù)執(zhí)行的,而從 Android 12 開始,它們將由加急作業(yè) (expedited job) 實(shí)現(xiàn)。
系統(tǒng)以配額的形式限制了加急工作的數(shù)量。當(dāng)應(yīng)用處于前臺(tái)時(shí),加急工作不存在任何配額限制,但是當(dāng)應(yīng)用轉(zhuǎn)到后臺(tái)運(yùn)行時(shí),就必須遵從這些限制。配額的大小取決于應(yīng)用的待機(jī)存儲(chǔ)分區(qū)和進(jìn)程重要性 (如優(yōu)先級(jí))。從字面意思來看,加急工作就是需要盡快啟動(dòng)執(zhí)行的工作,這意味著此類工作對(duì)于延遲相當(dāng)敏感,所以也就不支持設(shè)定初始延遲或是定期執(zhí)行的設(shè)置。由于受到配額限制,加急工作也不可以取代長(zhǎng)時(shí)間運(yùn)行的工作。當(dāng)您的用戶想要發(fā)送一條重要信息時(shí),WorkManager 會(huì)盡可能保證這條消息盡快發(fā)送。
class SendMessageWorker(context: Context, parameters: WorkerParameters): CoroutineWorker(context, parameters) {override suspend fun getForegroundInfo(): ForegroundInfo {TODO()}override suspend fun doWork(): Result {TODO()} }例如,一個(gè)同步聊天應(yīng)用消息的案例使用了加急工作 API。SendMessageWorker 類擴(kuò)展自 CoroutineWorker,而它的作用是負(fù)責(zé)從后臺(tái)為聊天應(yīng)用同步消息。加急工作需要在某個(gè)前臺(tái)服務(wù)的上下文中運(yùn)行,這很類似于 Android 12 之前版本中的長(zhǎng)時(shí)間運(yùn)行的工作。因此我們的 Worker 類還需要實(shí)現(xiàn) getForegroundInfo 接口,方便生成和顯示通知消息。但是在 Android 12 上 WorkManager 不會(huì)顯示其他的通知,這是因?yàn)槲覀兌x的 Worker 背后是由加急作業(yè)實(shí)現(xiàn)的。您需要像平常那樣實(shí)現(xiàn)一個(gè) suspend 標(biāo)記的 doWork 方法。需要注意的是,當(dāng)您的應(yīng)用占用了全部的配額后,加急作業(yè)可能會(huì)被中斷。因此我們的 Worker 最好能跟蹤某些狀態(tài),以便在重新安排執(zhí)行時(shí)間后能夠恢復(fù)運(yùn)行。
val request = OneTimeWorkRequestBuilder<ForegroundWorker>().setExpedited(OutOfQuotaPolicy.DROP_WORK_REQUEST).build()WorkManager.getInstance(context).enqueue(request)您可以使用 setExpedited API 來安排加急工作,這個(gè) API 會(huì)告訴 WorkManager,用戶認(rèn)為給定的工作請(qǐng)求非常重要。由于所能安排的工作存在配額限制,所以您需要表明當(dāng)應(yīng)用的配額用盡時(shí)該怎么處理,有兩種備選方案: 其一是將加急請(qǐng)求變成常規(guī)工作請(qǐng)求,其二是在配額耗盡時(shí)放棄新的工作請(qǐng)求。
從 2.5 版本開始,WorkManager 對(duì)支持多進(jìn)程的應(yīng)用進(jìn)行了若干項(xiàng)改進(jìn)。如果您需要使用多進(jìn)程 API,就需要定義 work-multiprocess 工件的依賴項(xiàng),多進(jìn)程 API 的目標(biāo)是在輔助進(jìn)程中對(duì) WorkManager 的冗余部分或高開銷部分進(jìn)行大范圍初始化操作。比如有多個(gè)進(jìn)程在同時(shí)獲取統(tǒng)一底層 SQLite 數(shù)據(jù)庫(kù)的事務(wù)鎖,這時(shí)就會(huì)發(fā)生 SQLite 爭(zhēng)用;而這種爭(zhēng)用正是我們想要通過多進(jìn)程 API 減少的。另一方面,我們還想確保進(jìn)程內(nèi)調(diào)度程序在正確的進(jìn)程中運(yùn)行。
為了解 WorkManager 初始化時(shí)哪些部分是冗余的,我們需要清楚它會(huì)在后臺(tái)執(zhí)行哪些操作。
單進(jìn)程的初始化
首先觀察一下單進(jìn)程初始化過程。應(yīng)用啟動(dòng)后,第一件事是有平臺(tái)調(diào)用 Application.onCreate 方法。隨后在進(jìn)程生命周期的某個(gè)時(shí)間點(diǎn),WorkManager.getInstance 會(huì)被調(diào)用以啟動(dòng) WorkManager 的初始化。當(dāng) WorkManager 初始化完畢后,我們運(yùn)行 ForceStopRunnable。這個(gè)過程很重要,因?yàn)榇藭r(shí) WorkManager 會(huì)檢查應(yīng)用之前是否被強(qiáng)制停止過,它會(huì)比較 WorkManager 存儲(chǔ)的信息與 JobScheduler 或 AlarmManager 中的信息,確保作業(yè)都被準(zhǔn)確編入執(zhí)行計(jì)劃中。同時(shí),我們也可以重新安排此前中斷的某些工作,比如進(jìn)程崩潰后進(jìn)行的一些恢復(fù)工作。大家都知道,這樣做的開銷非常高,我們需要在多個(gè)子系統(tǒng)中比較和協(xié)調(diào)狀態(tài),但是理想狀態(tài)下,這種操作只應(yīng)該被執(zhí)行一次。另外需要注意,進(jìn)程內(nèi)調(diào)度程序只在默認(rèn)進(jìn)程中運(yùn)行。
-
JobScheduler
https://developer.android.google.cn/reference/android/app/job/JobScheduler.html
-
AlarmManager
https://developer.android.google.cn/reference/android/app/AlarmManager
多進(jìn)程的初始化
接著我們?cè)倏纯慈绻麘?yīng)用有第二個(gè)進(jìn)程會(huì)發(fā)生什么。假如應(yīng)用有第二個(gè)進(jìn)程,基本上它會(huì)重復(fù)在第一個(gè)進(jìn)程中完成的各項(xiàng)操作。首先第一個(gè)進(jìn)程如上文那樣初始化,并且由于這是主進(jìn)程 (primary process),所以進(jìn)程內(nèi)調(diào)度程序 (In-Process Scheduler) 也會(huì)在其中運(yùn)行。對(duì)于第二個(gè)進(jìn)程,我們會(huì)重復(fù)剛才的過程,再次調(diào)用 Application.onCreate,然后重新初始化 WorkManager。這意味著,我們將重復(fù)在第一個(gè)進(jìn)程中所做的所有工作。
根據(jù)前面的分析,您也許會(huì)感到疑惑,為什么還需要再次執(zhí)行 ForceStopRunable 呢?這是由于 WorkManager 并不知道這些進(jìn)程中哪一個(gè)優(yōu)先級(jí)較高。如果應(yīng)用是屏幕鍵盤或者微件 (Widget),那么主進(jìn)程可能并不等同于默認(rèn)進(jìn)程。另外,輔助進(jìn)程 (secondary processes) 中也沒有運(yùn)行進(jìn)程內(nèi)調(diào)度程序 (因?yàn)樗皇悄J(rèn)進(jìn)程)。其實(shí)進(jìn)程內(nèi)調(diào)度程序所在的進(jìn)程選擇非常重要,由于它不受其他持久性調(diào)度器的限制影響,所以調(diào)整其所在的進(jìn)程可以顯著提升數(shù)據(jù)吞吐量。例如,JobScheduler 的作業(yè)上限是 100 個(gè),而進(jìn)程內(nèi)調(diào)度程序則沒有這個(gè)限制。
val config = Configuration.Builder().setDefaultProcessName("com.example.app").build()通過 WorkManager 定義主進(jìn)程
我們來看看如何定義指定的默認(rèn)進(jìn)程。首先根據(jù)自己的意愿設(shè)置默認(rèn)進(jìn)程的名稱,這通常是應(yīng)用的軟件包名稱,一旦定義了應(yīng)用的默認(rèn)進(jìn)程,那么進(jìn)程內(nèi)調(diào)度程序就會(huì)在其中運(yùn)行。但是輔助進(jìn)程怎么辦?有沒有辦法能夠防止在其中再次初始化 WorkManager?事實(shí)證明這是可以辦到的。其實(shí)我們真正需要的是完全不必初始化 WorkManager。
為了實(shí)現(xiàn)這個(gè)目標(biāo),我們引入了 RemoteWorkManager。這個(gè)類需要綁定到指定進(jìn)程 (主進(jìn)程),并使用綁定服務(wù)將次要進(jìn)程的所有工作請(qǐng)求轉(zhuǎn)發(fā)到這個(gè)指定的主進(jìn)程。這樣一來,您就可以完全避免所有剛才提到的跨進(jìn)程 SQLite 爭(zhēng)用,因?yàn)閺拈_始到結(jié)束只有唯一一個(gè)進(jìn)程在向底層 SQLite 數(shù)據(jù)庫(kù)寫入數(shù)據(jù)。您可以跟往常一樣在輔助進(jìn)程中創(chuàng)建工作請(qǐng)求,但是此處應(yīng)該使用 RemoteWorkManager 而不是 WorkManager。使用 RemoteWorkManager 后,會(huì)通過綁定服務(wù)綁定到主進(jìn)程中,并將所有工作請(qǐng)求進(jìn)行轉(zhuǎn)發(fā),然后存儲(chǔ)到特定隊(duì)列等待執(zhí)行。您可以通過將 RemoteWorkManager 服務(wù)合并到應(yīng)用的 Android Manifest RXML 中實(shí)現(xiàn)這個(gè)綁定。
val request = OneTimeWorkRequestBuilder<DownloadWorker>().build()RemoteWorkManager.getInstance(context).enqueue(request) <!-- AndroidManifest.xml --> <serviceandroid:name="androidx.work.multiprocess.RemoteWorkManagerService"android:exported="false" />不同進(jìn)程中運(yùn)行 Worker
我們已經(jīng)了解如何通過 WorkManager 定義主進(jìn)程來避免爭(zhēng)用,但有時(shí)候,您也希望能夠在不同的進(jìn)程中運(yùn)行 Worker。舉個(gè)例子,如果您在某應(yīng)用的輔助進(jìn)程中運(yùn)行機(jī)器學(xué)習(xí)工作流 (ML Pipeline),而且該應(yīng)用還有專門的界面進(jìn)程,那么您可能需要在不同的進(jìn)程中運(yùn)行不同的 Worker。比如在輔助進(jìn)程中隔離執(zhí)行某個(gè)工作,這樣一來即使這個(gè)進(jìn)程內(nèi)出現(xiàn)錯(cuò)誤而崩潰也不會(huì)導(dǎo)致應(yīng)用的其他部分癱瘓而整體退出,尤其是要保障界面進(jìn)程正常工作。要實(shí)現(xiàn)在不同進(jìn)程中執(zhí)行 Worker,您需要擴(kuò)展 RemoteCoroutineWorker 類。這個(gè)類與 CoroutineWorker 類似,擴(kuò)展之后您需要自己實(shí)現(xiàn) doRemoteWork 接口。
public class IndexingWorker(context: Context,parameters: WorkerParameters ): RemoteCoroutineWorker(context, parameters) {override suspend fun doRemoteWork(): Result {doSomething()return Result.success()} }由于這個(gè)方法是在輔助進(jìn)程中執(zhí)行的,我們?nèi)匀灰x Worker 需要與哪個(gè)進(jìn)程綁定。為此,我們還需要在 Android Manifest RXML 中添加一個(gè)條目。一個(gè)應(yīng)用可以定義多項(xiàng) RemoteWorker 服務(wù),每項(xiàng)服務(wù)都在獨(dú)立的進(jìn)程中運(yùn)行。
<!-- AndroidManifest.xml --> <serviceandroid:name="androidx.work.multiprocess.RemoteWorkerService"android:exported="false"android:process=":background" />這里您可以看到,我們?yōu)槊麨?background 的輔助進(jìn)程添加了新服務(wù)。現(xiàn)在,您已經(jīng)在 RXML 中定義好了服務(wù),還需要進(jìn)一步在工作請(qǐng)求中指明要綁定的組件名稱。
al inputData = workDataOf(ARGUMENT_PACKAGE_NAME to context.packageName,ARGUMENT_CLASS_NAME to RemoteWorkerService::class.java.name )val request = OneTimeWorkRequestBuilder<RemoteDownloadWorker>().setInputData(inputData).build()WorkManager.getInstance(context).enqueue(request)組件名稱是軟件包名和類名的組合,您需要將其添加到工作請(qǐng)求的輸入數(shù)據(jù)中,然后用這個(gè)輸入數(shù)據(jù)創(chuàng)建工作請(qǐng)求,這樣一來 WorkManager 就知道要綁定哪項(xiàng)服務(wù)了。我們照常將工作放入隊(duì)列中,當(dāng) WorkManager 準(zhǔn)備執(zhí)行這項(xiàng)工作時(shí),它首先根據(jù)輸入數(shù)據(jù)中定義的內(nèi)容找到綁定的服務(wù),并執(zhí)行 doRemoteWork 方法。這樣一來,所有復(fù)雜繁瑣的跨進(jìn)程通信的任務(wù)都交給 WorkManager 來處理了。
WorkManager 是應(yīng)對(duì)長(zhǎng)執(zhí)行時(shí)間工作的推薦方案,推薦您使用 WorkManager 實(shí)現(xiàn)請(qǐng)求和取消長(zhǎng)時(shí)間運(yùn)行的工作任務(wù)。通過本文了解到如何以及何時(shí)使用加急工作 API,如何編寫可靠的高性能多進(jìn)程應(yīng)用。
希望這篇文章對(duì)您有所幫助!
如需更多資源,請(qǐng)參閱:
-
Codelab: 使用 WorkManager 處理后臺(tái)任務(wù)
https://developer.android.google.cn/codelabs/android-workmanager -
Codelab: WorkManager 進(jìn)階知識(shí)
https://developer.android.google.cn/codelabs/android-adv-workmanager -
WorkManager 示例代碼
https://github.com/android/architecture-components-samples/tree/main/WorkManagerSample
總結(jié)
以上是生活随笔為你收集整理的使用 WorkManager 管理后台和前台工作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android基于Docker容器的双系
- 下一篇: Android多开和虚拟化--Docke