玩轉全新的 Android 8.0 Oreo 後臺策略
我們永遠都需要流暢的使用者體驗,但很遺憾我們手上的硬體資源卻總是和這個需求唱反調。這也是 Android 平臺不斷努力的切入點——從 API 26開始,Android 對後臺服務引入了嚴格的限制。基本上,除非您的應用在前臺執行,否則系統將在幾分鐘內停止應用的所有後臺服務。
由於對後臺服務的這些限制,JobScheduler 已經成為執行後臺任務的實際解決方案。對於熟悉服務的開發者來說,JobScheduler 使用起來通常很簡單,當然也存在少量例外。我們這次就來探討其中一個例外。
假如您正在搭建一個 Android TV 應用。頻道對電視應用非常重要,因此您的應用需要能夠執行至少五種與頻道有關的後臺操作:釋出頻道,向頻道新增節目,將有關頻道的日誌傳送到遠端伺服器,更新頻道的後設資料,以及刪除頻道。在 Android 8.0(Oreo)之前,這五個操作中的每一個都可以在後臺服務中實現。然而,從 API 26 開始,您必須明智地決定,哪些應該沿用原有的普通後臺 Service,哪些應該使用 JobService。
如果只考慮電視 App 的使用場景,上述五個操作裡,其實只有 “頻道釋出” 可以做成一個原有的普通後臺服務。在某些場合下,頻道釋出涉及三個步驟:首先使用者單擊按鈕開始該過程; 然後,應用啟動後臺操作來建立和提交出版物; 最後,使用者透過使用者介面以確認訂閱。至此您可以看到,釋出頻道需要使用者互動,因此需要可見的 Activity。所以,ChannelPublisherService 可以是一個 IntentService,負責處理後臺邏輯。您不應該在這裡使用 JobService,因為 JobService 會引入延遲,而使用者互動通常需要您的應用進行即時響應。
對於其他四個操作,您應該使用 JobService; 因為它們都可以在您的應用位於後臺時執行。所以您應該分別建立 ChannelProgramsJobService,ChannelLoggerJobService,ChannelMetadataJobService,和 ChannelDeletionJobService。
避免 JobId 衝突
由於以上所有的四個 JobService 都在處理 Channel 物件,您似乎可以方便地使用 channelId 作為 jobId。但是由於 JobService 在 Android Framework 中設計的方式,您不能這樣做。以下是 jobId 的官方描述:
應用為這個作業提供的 ID。 隨後呼叫取消,或建立相同 jobId 的作業,將會更新已經存在的同一個 ID 的作業。該 ID 在同一個 uid 的所有客戶端(不只是同一個應用包)中必須是唯一的。您需要確保該 ID 在應用更新時始終保持穩定,因此它可能不應該基於資源 ID。
根據以上的描述,即使您使用 4 個不同的 Java 物件(即 -JobService),也仍然不能使用 channelId來作為它們的 jobId。類級別的名稱空間不能幫助到您。
這確實是個問題。您需要一個穩定、可擴充套件的方式來將 channelId 和它的 jobId 關聯起來。而最糟的結果莫過於,由於 jobId 衝突,導致不同的頻道互相覆蓋操作。如果jobId 是 String 型別,而不是 Integer 型別的話,解決起來就很容易:ChannelProgramsJobService 的 jobId = "ChannelPrograms" + channelId, ChannelLoggerJobService 的 jobId = "ChannelLogs" + channelId,等等。但因為 jobId屬於 Integer 型別,而不屬於 String 型別,所以您就要設計一個智慧的系統,用來為您的作業生成可重複使用 jobId。
重點來了 —— 現在我們來聊聊 JobIdManager,看怎樣用它來解決這個問題。
JobIdManager 是一個類別,您可以根據自己的應用需求進行調整。對於目前談到的這個電視應用,基本構想是:使用一個 channelId 處理與 Channel 相關的所有作業 。下面我們先來看看這個樣本 JobIdManager 類的程式碼 ,然後再詳細討論。
public class JobIdManager { public static final int JOB_TYPE_CHANNEL_PROGRAMS = 1; public static final int JOB_TYPE_CHANNEL_METADATA = 2; public static final int JOB_TYPE_CHANNEL_DELETION = 3; public static final int JOB_TYPE_CHANNEL_LOGGER = 4; public static final int JOB_TYPE_USER_PREFS = 11; public static final int JOB_TYPE_USER_BEHAVIOR = 21; @IntDef(value = { JOB_TYPE_CHANNEL_PROGRAMS, JOB_TYPE_CHANNEL_METADATA, JOB_TYPE_CHANNEL_DELETION, JOB_TYPE_CHANNEL_LOGGER, JOB_TYPE_USER_PREFS, JOB_TYPE_USER_BEHAVIOR }) @Retention(RetentionPolicy.SOURCE) public @interface JobType { } //16-1 for short. Adjust per your needs private static final int JOB_TYPE_SHIFTS = 15; public static int getJobId(@JobType int jobType, int objectId) { if ( 0如您所見,JobIdManager 只需結合一個字首和 channelId 即可獲得 jobId。然而這種簡單優雅的解決方案只是冰山一角。我們來考慮一下假設條件和注意事項。
您必須能夠強制 channelId 成為一個 Short 型別,所以當您將 channelId 與一個字首結合後,您仍然會得到一個有效的 Java Integer。當然,嚴格來說,它不一定是 Short。只要您的字首和 channelId 組合成一個不溢位的 Integer,它就能有效運作。但邊際處理在堅實的軟體工程中至關重要。所以,除非您真的走投無路,否則就強制為 Short 型別吧。在實踐中,為遠端伺服器上具有較大 ID 的物件執行此操作的一種方法是,在本地資料庫或 content provider 中定義一個金鑰,並使用該金鑰生成您的jobId。
您的整個應用只應該有一個 JobIdManager 類。該類可以為應用的所有作業生成 jobId:無論這些工作是否與頻道、使用者或者其他任何事情有關。事實上我們的示例 JobIdManager 類指出了這一點:並不是所有 JOB_TYPE 都與 Channel 操作有關。一個作業型別與使用者偏好有關,一個與使用者行為有關。JobIdManager 透過為每個作業型別分配一個不同的字首來覆蓋以上種型別。
您的應用中的每個 -JobService,都必須擁有唯一和最終的 JOB_TYPE_ 字首。再強調一次,必須是徹底的一對一關係。
使用 JobIdManager
以下程式碼片段摘自 ChannelProgramsJobService,它為我們演示瞭如何在您的專案中使用 JobIdManager。無論何時需要安排新作業,都會使用 JobIdManager.getJobId(…) 生成 jobId。
import android.app.job.JobInfo;import android.app.job.JobParameters;import android.app.job.JobService;import android.content.ComponentName;import android.content.Context;import android.os.PersistableBundle;public class ChannelProgramsJobService extends JobService { private static final String CHANNEL_ID = "channelId"; . . public static void schedulePeriodicJob(Context context, final int channelId, String channelName, long intervalMillis, long flexMillis) { JobInfo.Builder builder = scheduleJob(context, channelId); builder.setPeriodic(intervalMillis, flexMillis); JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); if (JobScheduler.RESULT_SUCCESS != scheduler.schedule(builder.build())) { //todo what? log to server as analytics maybe? Log.d(TAG, "could not schedule program updates for channel " + channelName); } }private static JobInfo.Builder scheduleJob(Context context,final int channelId){ ComponentName componentName = new ComponentName(context, ChannelProgramsJobService.class); final int jobId = JobIdManager .getJobId(JobIdManager.JOB_TYPE_CHANNEL_PROGRAMS, channelId); PersistableBundle bundle = new PersistableBundle(); bundle.putInt(CHANNEL_ID, channelId); JobInfo.Builder builder = new JobInfo.Builder(jobId, componentName); builder.setPersisted(true); builder.setExtras(bundle); builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); return builder; } ... }相信看到這裡,您對如何針對不同的場景來設計後臺機制有了比較清晰的認識。但不管怎樣,從 Oreo 開始對後臺任務做出的種種限制都會對提升使用者體驗有著現實的意義,這也要求開發者們對自己的應用需要完成以及何時需要完成一些事情有著更精準的規劃。如果您有什麼問題,或者經驗之談,歡迎在下面和我們分享哦~
作者:谷歌開發者
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1817/viewspace-2803208/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android Oreo 後臺策略Android
- Android 8.0 Oreo 現已推出!Android
- Android Oreo 後臺執行限制Android
- Android 8.0 Oreo 推送通知的變化Android
- Android 8.0 Oreo 畫中畫模式Android模式
- Android 8.0 Oreo 國內可用測試平臺上線Android
- 【中文教學視訊】Android Oreo 中的後臺程式Android
- 中文視訊首發 | Android 8.0 Oreo 推送通知的變化Android
- Android 8.0 Oreo 之推送通知的變化 | 中文教學視訊Android
- Android 8.0 Oreo 開發者常見問題 | Android 開發者 FAQ Vol.7Android
- 玩轉策略模式模式
- Android8.0 後臺服務保活的一種思路Android
- Android8.0以上版本啟動後臺service報IllegalStateExceptionAndroidException
- 做了5年的Android,我轉Java後臺了!AndroidJava
- 最權威的 Android Oreo 新特性詳解Android
- [譯]玩轉 Android PathsAndroid
- Android 12 正式釋出 | 開發者們的全新舞臺Android
- 奧巴馬玩轉VR,稱其開創了一個全新的世界VR
- 【JS進階】教你在中後臺系統玩轉ES6JS
- MySQL 8.0 新密碼策略的細節補充MySql密碼
- Android 8.0 執行時許可權策略變化和適配方案Android
- 玩轉Android Jetpack系列之ViewModeAndroidJetpackView
- 【譯】如何用 TypeScript 玩轉後端?TypeScript後端
- Android Oreo 常見問題 2.0 | Android 開發者 FAQ Vol.9Android
- Android Oreo 常見問題 3.0 | Android 開發者 FAQ Vol.11Android
- 還在等著吃Android Oreo?Android P已經來了!!!Android
- Android Oreo 常見問題 2.0 | Android 開發者 FAQ Vol.9Android
- 玩轉Data Guard的switchover後切不回主庫
- Android 8.0 開發者 FAQAndroid
- oreo上的notification詳解
- Android Sunflower 帶您玩轉 JetpackAndroidJetpack
- MySQL8.0變化之密碼策略MySql密碼
- Android中的Gradle之玩轉自定義功能AndroidGradle
- 前後端分離後臺管理系統 Gfast v3.0 全新發布後端AST
- Android activity相互跳轉後臺出現兩個頁面的坑Android
- 社交電商平臺玩“會員”策略對營銷有哪些優勢?
- 活用Linux的後臺任務(轉)Linux
- WINDOWS9x 的後臺程式 (轉)Windows