【Android 电量优化】电量优化 ( JobScheduler | JobService | AsyncTask )

举报
韩曙亮 发表于 2022/01/11 00:28:59 2022/01/11
【摘要】 文章目录 一、JobScheduler 使用流程二、AsyncTask 简介三、JobScheduler 开发流程四、JobScheduler 代码示例1、JobScheduleManager 代...





一、JobScheduler 使用流程



JobScheduler 使用流程 :


① 获取 JobScheduler 服务 : 从 Context 对象中 , 调用 getSystemService 方法跨进程获取 ;

mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

  
 
  • 1

② 创建 JobInfo 任务信息 :

//创建一个任务
JobInfo jobInfo = new
        JobInfo.Builder(0,  // 任务 id 为 0
        new ComponentName(mContext, BpJobService.class))
        .setRequiresCharging(true)  // 要求在充电时执行
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非蜂窝网络执行
        .setExtras(extras).build();

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

③ 提交任务 :

mJobScheduler.schedule(jobInfo);

  
 
  • 1

④ 执行任务 : 在 JobService 的 onStartJob 方法中 , 会由系统在合适的时间 , 执行相关任务 ;

public class BpJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 启动 AsyncTask 异步任务处理工作
        new JobAsyncTask().execute(params);
        return false;
    }
    // ... 省略部分代码
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10




二、AsyncTask 简介



在 JobScheduler 提交任务后 , 系统会在 JobService 中执行相应的任务 , 执行的时机由系统选择 ;

系统回调 JobService 服务中的 onStartJob 方法时 , 由用户自行执行相应的任务 , 一般是使用 AsyncTask 来执行相应任务 ;


1 . AsyncTask<JobParameters, Void, Void> 三个泛型解析

  • 泛型 1 1 1 : 异步任务开始时 , execute 方法传入的参数类型
  • 泛型 2 2 2 : 异步任务执行时 , 进度值类型
  • 泛型 3 3 3 : 异步任务结束时 , 结果类型

2 . AsyncTask 4 4 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 , 处理添加任务的选项等操作 , 如任务执行时机 , 执行需求 等 ;

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);
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97


2、JobService 与 AsyncTask 代码示例


JobService 与 AsyncTask 代码示例 :


注意 JobService 的两个方法 onStartJob , onStopJob 的调用时机 , 与返回值含义 ;

注意 AsyncTask 定义时三个泛型的含义 , onPreExecute , doInBackground , onProgressUpdate , onPostExecute 四个方法的调用时机 ;

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);
        }
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94


3、AndroidManifest.xml 配置


主要是配置 AlarmManagerService 服务 和 BpJobService 服务 ;

注意为 BpJobService 服务声明 android.permission.BIND_JOB_SERVICE 权限 ;

<?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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62


4、执行结果


执行结果 :

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10




五、源码及资源下载



源码及资源下载地址 :

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/107141391

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。