文章目录
- 一、JobScheduler 使用流程
- 二、AsyncTask 简介
- 三、JobScheduler 开发流程
- 四、JobScheduler 代码示例
- 1、JobScheduleManager 代码示例
- 2、JobService 与 AsyncTask 代码示例
- 3、AndroidManifest.xml 配置
- 4、执行结果
- 五、源码及资源下载
一、JobScheduler 使用流程
JobScheduler 使用流程 :
① 获取 JobScheduler 服务 : 从 Context 对象中 , 调用 getSystemService 方法跨进程获取 ;
代码语言:javascript复制mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
② 创建 JobInfo 任务信息 :
代码语言:javascript复制//创建一个任务
JobInfo jobInfo = new
JobInfo.Builder(0, // 任务 id 为 0
new ComponentName(mContext, BpJobService.class))
.setRequiresCharging(true) // 要求在充电时执行
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非蜂窝网络执行
.setExtras(extras).build();
③ 提交任务 :
代码语言:javascript复制mJobScheduler.schedule(jobInfo);
④ 执行任务 : 在 JobService 的 onStartJob 方法中 , 会由系统在合适的时间 , 执行相关任务 ;
代码语言:javascript复制public class BpJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
// 启动 AsyncTask 异步任务处理工作
new JobAsyncTask().execute(params);
return false;
}
// ... 省略部分代码
}
二、AsyncTask 简介
在 JobScheduler 提交任务后 , 系统会在 JobService 中执行相应的任务 , 执行的时机由系统选择 ;
系统回调 JobService 服务中的 onStartJob 方法时 , 由用户自行执行相应的任务 , 一般是使用 AsyncTask 来执行相应任务 ;
1 . AsyncTask<JobParameters, Void, Void> 三个泛型解析
- 泛型
1: 异步任务开始时 , execute 方法传入的参数类型
- 泛型
2 : 异步任务执行时 , 进度值类型
- 泛型
3: 异步任务结束时 , 结果类型
2 . AsyncTask
4个方法解析 :
- onPreExecute : doInBackground 之前执行的方法, 一般在该方法中执行初始化操作 ( 主线程, 可以更新 UI )
- doInBackground : 主要的耗时操作是在该方法中执行的 ( 非主线程, 不能更新 UI )
- onProgressUpdate : 在 doInBackground 中调用了 publishProgress 方法, 就会回调该方法 , 一般情况下是在该方法中执行更新 UI 的操作 ( 主线程, 可以更新 UI )
- onPostExecute : doInBackground 执行完毕后 , 调用 return 方法后 , 该方法会被调用 ( 主线程, 可以更新 UI )
执行顺序 : onPreExecute -> doInBackground -> onProgressUpdate -> onPostExecute
三、JobScheduler 开发流程
1 . 任务管理类 : 开发 JobScheduleManager 管理类 , 该类负责与 Service 服务中的需求对接 , 接收 Service 服务中的添加任务的需求 , 将任务操作转为参数 , 并提交到系统 JobScheduler 中 ;
2 . 任务执行服务 : 开发 JobService 服务 , 该服务是执行具体的任务的类 , 在该类中 , 接收到系统调度的任务参数 , 在 onStartJob 方法中解析这些参数 , 并创建 AsyncTask 执行对应的任务 ;
3 . 添加任务 : 在一个第三方 Service 服务中 , 调用 JobScheduleManager 类添加任务 , 系统会自动回调分配执行任务 , 在 JobService 中的 onStartJob 方法中执行任务 ;
四、JobScheduler 代码示例
1、JobScheduleManager 代码示例
该类主要用于管理 JobScheduler , 初始化 JobScheduler , 处理添加任务的选项等操作 , 如任务执行时机 , 执行需求 等 ;
代码语言:javascript复制package kim.hsl.bp;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.os.PersistableBundle;
import android.util.Log;
import java.util.List;
public class JobScheduleManager {
public static final String TAG = "JobScheduleManager";
/**
* 将不紧急的任务调度到更合适的时机进行处理
* 如充电时 , 如 WIFI 连接时
* 1. 避免频繁由于执行单次任务 , 唤醒硬件模块 , 造成电量浪费
* 2. 避免在不合适的时机执行耗电任务 , 如使用蜂窝网络在不合适的时候更新软件
*/
private JobScheduler mJobScheduler;
/**
* 上下文对象
*/
private Context mContext;
/*
单例模式
*/
private static JobScheduleManager mInstance;
private JobScheduleManager(){}
public static JobScheduleManager getInstance(){
if(mInstance == null){
mInstance = new JobScheduleManager();
}
return mInstance;
}
public void init(Context context){
this.mContext = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
}
}
public void addJob(String currentJobData){
if(mJobScheduler == null){
return;
}
Log.i(TAG, "添加任务 : " currentJobData);
// 查找 id 为 0 的 任务
JobInfo pendingJob = null;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
pendingJob = mJobScheduler.getPendingJob(0);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
List<JobInfo> allPendingJobs = mJobScheduler.getAllPendingJobs();
for(JobInfo info : allPendingJobs){
if(info.getId() == 0){
pendingJob = info;
break;
}
}
}
// 获取任务执行数据
String historyJobData = "";
if(pendingJob != null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
PersistableBundle extras = pendingJob.getExtras();
historyJobData = extras.getString("JOB_DATA");
mJobScheduler.cancel(0);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
PersistableBundle extras = new PersistableBundle();
extras.putString("JOB_DATA", currentJobData "$" historyJobData);
//创建一个任务
JobInfo jobInfo = new
JobInfo.Builder(0, // 任务 id 为 0
new ComponentName(mContext, BpJobService.class))
.setRequiresCharging(true) // 要求在充电时执行
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非蜂窝网络执行
.setExtras(extras).build();
// 将任务提交到队列中
mJobScheduler.schedule(jobInfo);
}
}
}
2、JobService 与 AsyncTask 代码示例
JobService 与 AsyncTask 代码示例 :
注意 JobService 的两个方法 onStartJob , onStopJob 的调用时机 , 与返回值含义 ;
注意 AsyncTask 定义时三个泛型的含义 , onPreExecute , doInBackground , onProgressUpdate , onPostExecute 四个方法的调用时机 ;
代码语言:javascript复制package kim.hsl.bp;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.os.AsyncTask;
import android.os.Build;
import android.os.PersistableBundle;
import android.util.Log;
import androidx.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class BpJobService extends JobService {
public static final String TAG = "Battery_Performance.BpJobService";
/**
*
* @param params
* @return
* true 任务正要被执行, 需要开始执行任务
* false 任务执行完毕
*/
@Override
public boolean onStartJob(JobParameters params) {
// 启动 AsyncTask 异步任务处理工作
new JobAsyncTask().execute(params);
return false;
}
/**
*
* @param params
* @return
*/
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
/**
* AsyncTask<JobParameters, Void, Void> 三个泛型解析
* -- 1. 异步任务开始时 , execute 方法传入的参数类型
* -- 2. 异步任务执行时 , 进度值类型
* -- 3. 异步任务结束时 , 结果类型
*/
class JobAsyncTask extends AsyncTask<JobParameters, Void, Void> {
/**
* doInBackground 之前执行的方法, 一般在该方法中执行初始化操作
* ( 主线程, 可以更新 UI )
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 主要的耗时操作是在该方法中执行的
* ( 非主线程, 不能更新 UI )
* @param jobParameters
* @return
*/
@Override
protected Void doInBackground(JobParameters... jobParameters) {
JobParameters parameters = jobParameters[0];
PersistableBundle extras = parameters.getExtras();
String jobData = extras.getString("JOB_DATA");
Log.i(TAG, "JobAsyncTask 执行 : " jobData);
return null;
}
/**
* 在 doInBackground 中调用了 publishProgress 方法, 就会回调该方法
* 一般情况下是在该方法中执行更新 UI 的操作
* ( 主线程, 可以更新 UI )
* @param values
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* doInBackground 执行完毕后 , 调用 return 方法后 , 该方法会被调用
* ( 主线程, 可以更新 UI )
* @param aVoid
*/
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
}
3、AndroidManifest.xml 配置
主要是配置 AlarmManagerService 服务 和 BpJobService 服务 ;
注意为 BpJobService 服务声明 android.permission.BIND_JOB_SERVICE 权限 ;
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="kim.hsl.bp">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BatteryReceiver" >
<intent-filter>
<!-- 充电线插上 -->
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<!-- 充电线拔出 -->
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<receiver android:name=".WifiReceiver" >
<intent-filter>
<!-- 网络状态改变 -->
<action android:name="android.intent.action.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<!-- WeakLock 保持 CPU 唤醒的 Service 服务 -->
<service
android:name=".WeakLockService"
android:process=":weaklock" />
<!-- AlarmManager 保持 CPU 唤醒的 Service 服务 -->
<service
android:name=".AlarmManagerService"
android:process=":alrmmanager" />
<!-- JobScheduler 服务 -->
<service
android:name=".BpJobService"
android:process=":jobservice"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>
4、执行结果
执行结果 :
代码语言:javascript复制2020-07-07 15:00:58.189 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: AlarmManagerService onCreate
2020-07-07 15:01:19.056 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION
2020-07-07 15:01:19.057 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.JobScheduleManager: 添加任务 : ACTION(1594105279057)
2020-07-07 15:01:19.239 11158-11214/kim.hsl.bp:jobservice I/Battery_Performance.BpJobService: JobAsyncTask 执行 : ACTION(1594105279057)$
2020-07-07 15:02:38.985 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION
2020-07-07 15:02:38.986 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.JobScheduleManager: 添加任务 : ACTION(1594105358986)
2020-07-07 15:02:38.997 11158-11214/kim.hsl.bp:jobservice I/Battery_Performance.BpJobService: JobAsyncTask 执行 : ACTION(1594105358986)$
2020-07-07 15:03:19.058 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION
五、源码及资源下载
源码及资源下载地址 :
- ① GitHub 工程地址 : Battery_Performance
- ② 使用 AlarmManager 保持 CPU 唤醒 Service 代码地址 : AlarmManagerService.java
- ③ JobScheduleManager.java 代码地址 : JobScheduleManager.java
- ④ BpJobService.java 代码地址 : BpJobService.java
- ⑤ AndroidManifest.xml 配置文件地址 : AndroidManifest.xml