簡評: Android 實現後臺任務的最佳實踐。
對於現在的應用來說,在應用生命週期之外運行一些後臺任務可以說已經是一項必不可少的需求了。這些任務可能是在某個時間點提醒用戶什麼事情或同步本地數據到服務器等等。
對此 Android 有一系列方式來實現這些後臺任務:
1. JobSchedular
JobSchedular 在 Lollipop (API level 21) 中被引入,也是目前實現後臺任務最有效的手段。其根據條件來執行任務,具體條件可能是「設備連接上了網絡」、「正在充電」...
官方文檔對此已經講得很詳細了。
2. GCM Network Manager(目前已更新爲 FCM)
GCM Network Manager 提供的 API 和 JobSchedular 很相似,支持 API 9 及以上。唯一的問題就在於是屬於 Google Play Service SDK 的一部分,所以這裏就不多說了。
3. AlarmManager
JobSchedular 和 GCM Network Manager 可以基於條件定義任務,比如網絡連接狀態改變、充電狀態改變,這些都不屬於會在某個固定時間點觸發的後臺任務。但有時你的應用可能需要在某個固定時間點觸發一個通知、週期性的任務什麼的。或者針對 API level 21 以下,又沒有集成 Google Play Service SDK 的應用實現一些後臺任務功能。這時就可以考慮使用 AlarmManager。
遇見 Android-Job
可以看到三個方案都有各自的優缺點,爲了解決這個問題,Evernote 開源了 Android-Job 這個非常出色的項目。
Android-Job 能根據當前系統的版本,是否集成 Google Play Service SDK 和要執行的任務類型調用不同的 API,兼容當前主流版本。
集成:
apply plugin: 'com.android.application'
android {
...
}
dependencies {
...
compile 'com.evernote:android-job:1.1.8'
}
使用:
Android-Job 主要包含了下面四個類/接口:
- Job:所有我們的 Job 都需要繼承它,並實現 onRunJob 方法。
- JobRequest:用來定義一個具體的任務(Job)。
- JobCreator:根據任務的 tag 來創建任務。
- JobManager:android-job 的入口。
示例:
我們來創建一個「展示通知任務」。首先,實現 Job:
class ShowNotificationJob extends Job {
static final String TAG = "show_notification_job_tag";
@NonNull
@Override
protected Result onRunJob(Params params) {
PendingIntent pi = PendingIntent.getActivity(getContext(), 0,
new Intent(getContext(), MainActivity.class), 0);
Notification notification = new NotificationCompat.Builder(getContext())
.setContentTitle("Android Job Demo")
.setContentText("Notification from Android Job Demo App.")
.setAutoCancel(true)
.setContentIntent(pi)
.setSmallIcon(R.mipmap.ic_launcher)
.setShowWhen(true)
.setColor(Color.RED)
.setLocalOnly(true)
.build();
NotificationManagerCompat.from(getContext())
.notify(new Random().nextInt(), notification);
return Result.SUCCESS;
}
static void schedulePeriodic() {
new JobRequest.Builder(ShowNotificationJob.TAG)
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(5))
.setUpdateCurrent(true)
.setPersisted(true)
.build()
.schedule();
}
}
可以看到其中我們通過 JobRequest 來安排一個任務,任務的 tag 作爲一個任務的唯一標識。
其中 JobRequest 包含了很多的方法,都在項目的 Github 頁面中有詳細的說明。
之後,實現 JobCreator 接口:
class DemoJobCreator implements JobCreator {
@Override
public Job create(String tag) {
switch (tag) {
case ShowNotificationJob.TAG:
return new ShowNotificationJob();
default:
return null;
}
}
}
可以看到這裏是需要根據 Job 的 tag 來創建任務的。然後,在我們應用的自定義 Application 類裏註冊 JobCreator :
public class MainApp extends Application {
@Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new DemoJobCreator());
}
}
最後,在需要的地方註冊任務:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ShowNotificationJob.schedulePeriodic();
}
}
是不是很簡單。不再需要自己去考慮什麼情況該用哪種方案了,只需要這樣統一的實現就可以啦。
順便分享一個 debug 的小 tip。當我們在 debug 的時候,往往會把間隔時間調短從而可以馬上看到效果。但是在 Android N 中,規定了定時任務間隔最少爲 15 分鐘,如果小於 15 分鐘會得到一個錯誤:intervalMs is out of range
這時,可以調用 JobManager 的 setAllowSmallerIntervalsForMarshmallow(true)
方法在 debug 模式下避免這個問題。但在正式環境下一定要注意間隔時間設置爲** 15 分鐘以上**。
public class MainApp extends Application {
@Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new DemoJobCreator());
JobManager.instance().getConfig().setAllowSmallerIntervalsForMarshmallow(true); // Don't use this in production
}
}
原文鏈接:Easy Job Scheduling with Android-Job
推薦閱讀:Android - Spring Animation,讓應用的 View 像彈簧一樣動起來